nulogy-gettext_i18n_rails 0.4.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/Gemfile +16 -0
  2. data/Gemfile.lock +126 -0
  3. data/Rakefile +24 -0
  4. data/Readme.md +226 -0
  5. data/VERSION +1 -0
  6. data/gettext_i18n_rails.gemspec +65 -0
  7. data/init.rb +14 -0
  8. data/lib/gettext_i18n_rails.rb +33 -0
  9. data/lib/gettext_i18n_rails/action_controller.rb +8 -0
  10. data/lib/gettext_i18n_rails/active_record.rb +19 -0
  11. data/lib/gettext_i18n_rails/backend.rb +67 -0
  12. data/lib/gettext_i18n_rails/base_parser.rb +41 -0
  13. data/lib/gettext_i18n_rails/haml_parser.rb +15 -0
  14. data/lib/gettext_i18n_rails/hamlet_parser.rb +16 -0
  15. data/lib/gettext_i18n_rails/html_safe_translations.rb +29 -0
  16. data/lib/gettext_i18n_rails/i18n_hacks.rb +25 -0
  17. data/lib/gettext_i18n_rails/model_attributes_finder.rb +108 -0
  18. data/lib/gettext_i18n_rails/railtie.rb +22 -0
  19. data/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +144 -0
  20. data/lib/gettext_i18n_rails/slim_parser.rb +15 -0
  21. data/lib/gettext_i18n_rails/string_interpolate_fix.rb +20 -0
  22. data/lib/gettext_i18n_rails/tasks.rb +127 -0
  23. data/lib/tasks/gettext_rails_i18n.rake +1 -0
  24. data/spec/gettext_i18n_rails/action_controller_spec.rb +54 -0
  25. data/spec/gettext_i18n_rails/active_record_spec.rb +85 -0
  26. data/spec/gettext_i18n_rails/backend_spec.rb +56 -0
  27. data/spec/gettext_i18n_rails/haml_parser_spec.rb +39 -0
  28. data/spec/gettext_i18n_rails/hamlet_parser_spec.rb +33 -0
  29. data/spec/gettext_i18n_rails/slim_parser_spec.rb +40 -0
  30. data/spec/gettext_i18n_rails/string_interpolate_fix_spec.rb +32 -0
  31. data/spec/gettext_i18n_rails_spec.rb +84 -0
  32. data/spec/spec_helper.rb +39 -0
  33. metadata +110 -0
@@ -0,0 +1,15 @@
1
+ require 'gettext_i18n_rails/base_parser'
2
+
3
+ module GettextI18nRails
4
+ class SlimParser < BaseParser
5
+ def self.extension
6
+ "slim"
7
+ end
8
+
9
+ def self.convert_to_code(text)
10
+ Slim::Engine.new.call(text)
11
+ end
12
+ end
13
+ end
14
+
15
+ GetText::RGetText.add_parser(GettextI18nRails::SlimParser)
@@ -0,0 +1,20 @@
1
+ needed = "".respond_to?(:html_safe) and
2
+ (
3
+ "".html_safe % {:x => '<br/>'} == '<br/>' or
4
+ not ("".html_safe % {:x=>'a'}).html_safe?
5
+ )
6
+
7
+ if needed
8
+ class String
9
+ alias :interpolate_without_html_safe :%
10
+
11
+ def %(*args)
12
+ if args.first.is_a?(Hash) and html_safe?
13
+ safe_replacement = Hash[args.first.map{|k,v| [k,ERB::Util.h(v)] }]
14
+ interpolate_without_html_safe(safe_replacement).html_safe
15
+ else
16
+ interpolate_without_html_safe(*args).dup # make sure its not html_safe
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,127 @@
1
+ namespace :gettext do
2
+ def load_gettext
3
+ require 'gettext'
4
+ require 'gettext/utils'
5
+ end
6
+
7
+ desc "Create mo-files for L10n"
8
+ task :pack => :environment do
9
+ load_gettext
10
+ GetText.create_mofiles(true, locale_path, locale_path)
11
+ end
12
+
13
+ desc "Update pot/po files."
14
+ task :find => :environment do
15
+ load_gettext
16
+ $LOAD_PATH << File.join(File.dirname(__FILE__),'..','..','lib')
17
+ require 'gettext_i18n_rails/haml_parser'
18
+ require 'gettext_i18n_rails/slim_parser'
19
+ require 'gettext_i18n_rails/hamlet_parser'
20
+
21
+
22
+ if GetText.respond_to? :update_pofiles_org
23
+ if defined?(Rails.application)
24
+ msgmerge = Rails.application.config.gettext_i18n_rails.msgmerge
25
+ end
26
+ msgmerge ||= %w[--sort-output --no-location --no-wrap]
27
+
28
+ GetText.update_pofiles_org(
29
+ text_domain,
30
+ files_to_translate,
31
+ "version 0.0.1",
32
+ :po_root => locale_path,
33
+ :msgmerge => msgmerge
34
+ )
35
+ else #we are on a version < 2.0
36
+ puts "install new GetText with gettext:install to gain more features..."
37
+ #kill ar parser...
38
+ require 'gettext/parser/active_record'
39
+ module GetText
40
+ module ActiveRecordParser
41
+ module_function
42
+ def init(x);end
43
+ end
44
+ end
45
+
46
+ #parse files.. (models are simply parsed as ruby files)
47
+ GetText.update_pofiles(
48
+ text_domain,
49
+ files_to_translate,
50
+ "version 0.0.1",
51
+ locale_path
52
+ )
53
+ end
54
+ end
55
+
56
+ # This is more of an example, ignoring
57
+ # the columns/tables that mostly do not need translation.
58
+ # This can also be done with GetText::ActiveRecord
59
+ # but this crashed too often for me, and
60
+ # IMO which column should/should-not be translated does not
61
+ # belong into the model
62
+ #
63
+ # You can get your translations from GetText::ActiveRecord
64
+ # by adding this to you gettext:find task
65
+ #
66
+ # require 'active_record'
67
+ # gem "gettext_activerecord", '>=0.1.0' #download and install from github
68
+ # require 'gettext_activerecord/parser'
69
+ desc "write the model attributes to <locale_path>/model_attributes.rb"
70
+ task :store_model_attributes => :environment do
71
+ FastGettext.silence_errors
72
+
73
+ require 'gettext_i18n_rails/model_attributes_finder'
74
+ require 'gettext_i18n_rails/active_record'
75
+
76
+ storage_file = "#{locale_path}/model_attributes.rb"
77
+ puts "writing model translations to: #{storage_file}"
78
+
79
+ ignore_tables = [/^sitemap_/, /_versions$/, 'schema_migrations', 'sessions', 'delayed_jobs']
80
+ GettextI18nRails.store_model_attributes(
81
+ :to => storage_file,
82
+ :ignore_columns => ['id', 'type', 'created_at', 'updated_at'],
83
+ :ignore_tables => ignore_tables
84
+ )
85
+ end
86
+
87
+ desc "add a new language"
88
+ task :add_language, [:language] => :environment do |_, args|
89
+ language = args.language || ENV["LANGUAGE"]
90
+
91
+ # Let's do some pre-verification of the environment.
92
+ if language.nil?
93
+ puts "You need to specify the language to add. Either 'LANGUAGE=eo rake gettext:add_languange' or 'rake gettext:add_languange[eo]'"
94
+ next
95
+ end
96
+ pot = File.join(locale_path, "#{text_domain}.pot")
97
+ if !File.exists? pot
98
+ puts "You don't have a pot file yet, you probably should run 'rake gettext:find' at least once. Tried '#{pot}'."
99
+ next
100
+ end
101
+
102
+ # Create the directory for the new language.
103
+ dir = File.join(locale_path, language)
104
+ puts "Creating directory #{dir}"
105
+ Dir.mkdir dir
106
+
107
+ # Create the po file for the new language.
108
+ new_po = File.join(locale_path, language, "#{text_domain}.po")
109
+ puts "Initializing #{new_po} from #{pot}."
110
+ system "msginit --locale=#{language} --input=#{pot} --output=#{new_po}"
111
+ end
112
+
113
+ def locale_path
114
+ FastGettext.translation_repositories[text_domain].instance_variable_get(:@options)[:path]
115
+ rescue
116
+ File.join(Rails.root, "locale")
117
+ end
118
+
119
+ def text_domain
120
+ # if your textdomain is not 'app': require the environment before calling e.g. gettext:find OR add TEXTDOMAIN=my_domain
121
+ ENV['TEXTDOMAIN'] || (FastGettext.text_domain rescue nil) || "app"
122
+ end
123
+
124
+ def files_to_translate
125
+ Dir.glob("{app,lib,config,#{locale_path}}/**/*.{rb,erb,haml,slim}")
126
+ end
127
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "/../gettext_i18n_rails/tasks")
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ FastGettext.silence_errors
4
+
5
+ describe ActionController::Base do
6
+ def reset!
7
+ fake_session = {}
8
+ @c.stub!(:session).and_return fake_session
9
+ fake_cookies = {}
10
+ @c.stub!(:cookies).and_return fake_cookies
11
+ @c.params = {}
12
+ @c.request = stub(:env => {})
13
+ end
14
+
15
+ before do
16
+ #controller
17
+ @c = ActionController::Base.new
18
+ reset!
19
+
20
+ #locale
21
+ FastGettext.available_locales = nil
22
+ FastGettext.locale = I18n.default_locale = 'fr'
23
+ FastGettext.available_locales = ['fr','en']
24
+ end
25
+
26
+ it "changes the locale" do
27
+ @c.params = {:locale=>'en'}
28
+ @c.set_gettext_locale
29
+ @c.session[:locale].should == 'en'
30
+ FastGettext.locale.should == 'en'
31
+ end
32
+
33
+ it "stays with default locale when none was found" do
34
+ @c.set_gettext_locale
35
+ @c.session[:locale].should == 'fr'
36
+ FastGettext.locale.should == 'fr'
37
+ end
38
+
39
+ it "locale isn't cached over request" do
40
+ @c.params = {:locale=>'en'}
41
+ @c.set_gettext_locale
42
+ @c.session[:locale].should == 'en'
43
+
44
+ reset!
45
+ @c.set_gettext_locale
46
+ @c.session[:locale].should == 'fr'
47
+ end
48
+
49
+ it "reads the locale from the HTTP_ACCEPT_LANGUAGE" do
50
+ @c.request.stub!(:env).and_return 'HTTP_ACCEPT_LANGUAGE'=>'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3'
51
+ @c.set_gettext_locale
52
+ FastGettext.locale.should == 'en'
53
+ end
54
+ end
@@ -0,0 +1,85 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ FastGettext.silence_errors
5
+
6
+ ActiveRecord::Base.establish_connection({
7
+ :adapter => "sqlite3",
8
+ :database => ":memory:",
9
+ })
10
+
11
+ ActiveRecord::Schema.define(:version => 1) do
12
+ create_table :car_seats, :force=>true do |t|
13
+ t.string :seat_color
14
+ end
15
+
16
+ create_table :parts, :force=>true do |t|
17
+ t.string :name
18
+ t.references :car_seat
19
+ end
20
+ end
21
+
22
+ ActiveRecord::Base.extend GettextI18nRails::ActiveRecord
23
+
24
+ class CarSeat < ActiveRecord::Base
25
+ validates_presence_of :seat_color, :message=>"translate me"
26
+ has_many :parts
27
+ accepts_nested_attributes_for :parts
28
+ end
29
+
30
+ class Part < ActiveRecord::Base
31
+ belongs_to :car_seat
32
+ end
33
+
34
+ describe ActiveRecord::Base do
35
+ before do
36
+ FastGettext.current_cache = {}
37
+ end
38
+
39
+ describe :human_name do
40
+ it "is translated through FastGettext" do
41
+ CarSeat.should_receive(:_).with('car seat').and_return('Autositz')
42
+ CarSeat.human_name.should == 'Autositz'
43
+ end
44
+ end
45
+
46
+ describe :human_attribute_name do
47
+ it "translates attributes through FastGettext" do
48
+ CarSeat.should_receive(:s_).with('CarSeat|Seat color').and_return('Sitz farbe')
49
+ CarSeat.human_attribute_name(:seat_color).should == 'Sitz farbe'
50
+ end
51
+
52
+ it "translates nested attributes through FastGettext" do
53
+ CarSeat.should_receive(:s_).with('CarSeat|Parts|Name').and_return('Handle')
54
+ CarSeat.human_attribute_name(:"parts.name").should == 'Handle'
55
+ end
56
+ end
57
+
58
+ describe 'error messages' do
59
+ let(:model){
60
+ c = CarSeat.new
61
+ c.valid?
62
+ c
63
+ }
64
+
65
+ it "translates error messages" do
66
+ FastGettext.stub!(:current_repository).and_return('translate me'=>"Übersetz mich!")
67
+ FastGettext._('translate me').should == "Übersetz mich!"
68
+ model.errors[:seat_color].should == ["Übersetz mich!"]
69
+ end
70
+
71
+ it "translates scoped error messages" do
72
+ pending 'scope is no longer added in 3.x' if ActiveRecord::VERSION::MAJOR >= 3
73
+ FastGettext.stub!(:current_repository).and_return('activerecord.errors.translate me'=>"Übersetz mich!")
74
+ FastGettext._('activerecord.errors.translate me').should == "Übersetz mich!"
75
+ model.errors[:seat_color].should == ["Übersetz mich!"]
76
+ end
77
+
78
+ it "translates error messages with %{fn}" do
79
+ pending
80
+ FastGettext.stub!(:current_repository).and_return('translate me'=>"Übersetz %{fn} mich!")
81
+ FastGettext._('translate me').should == "Übersetz %{fn} mich!"
82
+ model.errors[:seat_color].should == ["Übersetz car_seat mich!"]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,56 @@
1
+ require "spec_helper"
2
+
3
+ FastGettext.silence_errors
4
+
5
+ describe GettextI18nRails::Backend do
6
+ it "redirects calls to another I18n backend" do
7
+ subject.backend.should_receive(:xxx).with(1,2)
8
+ subject.xxx(1,2)
9
+ end
10
+
11
+ describe :available_locales do
12
+ it "maps them to FastGettext" do
13
+ FastGettext.should_receive(:available_locales).and_return [:xxx]
14
+ subject.available_locales.should == [:xxx]
15
+ end
16
+
17
+ it "and returns an empty array when FastGettext.available_locales is nil" do
18
+ FastGettext.should_receive(:available_locales).and_return nil
19
+ subject.available_locales.should == []
20
+ end
21
+ end
22
+
23
+ describe :translate do
24
+ it "uses gettext when the key is translatable" do
25
+ FastGettext.stub(:current_repository).and_return 'xy.z.u'=>'a'
26
+ subject.translate('xx','u',:scope=>['xy','z']).should == 'a'
27
+ end
28
+
29
+ it "interpolates options" do
30
+ FastGettext.stub(:current_repository).and_return 'ab.c'=>'a%{a}b'
31
+ subject.translate('xx','c',:scope=>['ab'], :a => 'X').should == 'aXb'
32
+ end
33
+
34
+ it "can translate with gettext using symbols" do
35
+ FastGettext.stub(:current_repository).and_return 'xy.z.v'=>'a'
36
+ subject.translate('xx',:v ,:scope=>['xy','z']).should == 'a'
37
+ end
38
+
39
+ it "can translate with gettext using a flat scope" do
40
+ FastGettext.stub(:current_repository).and_return 'xy.z.x'=>'a'
41
+ subject.translate('xx',:x ,:scope=>'xy.z').should == 'a'
42
+ end
43
+
44
+ # TODO NameError is raised <-> wtf ?
45
+ xit "uses the super when the key is not translatable" do
46
+ lambda{subject.translate('xx','y',:scope=>['xy','z'])}.should raise_error(I18n::MissingTranslationData)
47
+ end
48
+ end
49
+
50
+ describe :interpolate do
51
+ it "act as an identity function for an array" do
52
+ translation = [:month, :day, :year]
53
+ subject.send(:interpolate, translation, {}).should == translation
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+ require "gettext_i18n_rails/haml_parser"
3
+
4
+ describe GettextI18nRails::HamlParser do
5
+ let(:parser){ GettextI18nRails::HamlParser }
6
+
7
+ describe "#target?" do
8
+ it "targets .haml" do
9
+ parser.target?('foo/bar/xxx.haml').should == true
10
+ end
11
+
12
+ it "does not target anything else" do
13
+ parser.target?('foo/bar/xxx.erb').should == false
14
+ end
15
+ end
16
+
17
+ describe "#parse" do
18
+ it "finds messages in haml" do
19
+ with_file '= _("xxxx")' do |path|
20
+ parser.parse(path, []).should == [
21
+ ["xxxx", "#{path}:1"]
22
+ ]
23
+ end
24
+ end
25
+
26
+ it "ignores 1.9 errors" do
27
+ with_file '= _("xxxx", x: 1)' do |path|
28
+ $stderr.should_receive(:puts).with{|x| x =~ /file ignored/ }
29
+ parser.parse(path, [1]).should == [1]
30
+ end
31
+ end
32
+
33
+ it "does not find messages in text" do
34
+ with_file '_("xxxx")' do |path|
35
+ parser.parse(path, []).should == []
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+ require "gettext_i18n_rails/hamlet_parser"
3
+
4
+ describe GettextI18nRails::HamletParser do
5
+ let(:parser){ GettextI18nRails::HamletParser }
6
+
7
+ describe "#target?" do
8
+ it "targets .hamlet" do
9
+ parser.target?('foo/bar/xxx.hamlet').should == true
10
+ end
11
+
12
+ it "does not target anything else" do
13
+ parser.target?('foo/bar/xxx.erb').should == false
14
+ end
15
+ end
16
+
17
+ describe "#parse" do
18
+ it "finds messages in slim" do
19
+ with_file '<div>= _("xxxx")' do |path|
20
+ parser.parse(path, []).should == [
21
+ ["xxxx", "#{path}:1"]
22
+ ]
23
+ end
24
+ end
25
+
26
+ it "does not find messages in text" do
27
+ with_file '<div> _("xxxx")' do |path|
28
+ parser.parse(path, []).should == []
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "gettext_i18n_rails/slim_parser"
3
+
4
+ describe GettextI18nRails::SlimParser do
5
+ let(:parser){ GettextI18nRails::SlimParser }
6
+
7
+ describe "#target?" do
8
+ it "targets .slim" do
9
+ parser.target?('foo/bar/xxx.slim').should == true
10
+ end
11
+
12
+ it "does not target anything else" do
13
+ parser.target?('foo/bar/xxx.erb').should == false
14
+ end
15
+ end
16
+
17
+ describe "#parse" do
18
+ it "finds messages in slim" do
19
+ with_file 'div = _("xxxx")' do |path|
20
+ parser.parse(path, []).should == [
21
+ ["xxxx", "#{path}:1"]
22
+ ]
23
+ end
24
+ end
25
+
26
+ xit "can parse 1.9 syntax" do
27
+ with_file 'div = _("xxxx", foo: :bar)' do |path|
28
+ parser.parse(path, []).should == [
29
+ ["xxxx", "#{path}:1"]
30
+ ]
31
+ end
32
+ end
33
+
34
+ it "does not find messages in text" do
35
+ with_file 'div _("xxxx")' do |path|
36
+ parser.parse(path, []).should == []
37
+ end
38
+ end
39
+ end
40
+ end