lastobelus-merb_global 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/activerecord_generators/translations_migration/USAGE +4 -0
- data/activerecord_generators/translations_migration/templates/translations_migration.erb +30 -0
- data/activerecord_generators/translations_migration/translations_migration_generator.rb +31 -0
- data/examples/active_record_example/README.txt +9 -0
- data/examples/active_record_example/application.rb +5 -0
- data/examples/active_record_example/config/database.yml +9 -0
- data/examples/active_record_example/config/framework.rb +5 -0
- data/examples/active_record_example/config/init.rb +24 -0
- data/examples/active_record_example/config/plugins.yml +3 -0
- data/examples/data_mapper_example/README.txt +9 -0
- data/examples/data_mapper_example/application.rb +5 -0
- data/examples/data_mapper_example/config/database.yml +9 -0
- data/examples/data_mapper_example/config/framework.rb +5 -0
- data/examples/data_mapper_example/config/init.rb +24 -0
- data/examples/data_mapper_example/config/plugins.yml +3 -0
- data/examples/database.sql +28 -0
- data/examples/gettext_example/README.txt +9 -0
- data/examples/gettext_example/application.rb +8 -0
- data/examples/gettext_example/config/framework.rb +5 -0
- data/examples/gettext_example/config/init.rb +24 -0
- data/examples/gettext_example/config/plugins.yml +4 -0
- data/examples/gettext_example/locale/merbapp.pot +21 -0
- data/examples/gettext_example/locale/pl/LC_MESSAGES/merbapp.mo +0 -0
- data/examples/gettext_example/locale/pl.po +23 -0
- data/examples/mock_example/README.txt +9 -0
- data/examples/mock_example/application.rb +5 -0
- data/examples/mock_example/config/framework.rb +5 -0
- data/examples/mock_example/config/init.rb +23 -0
- data/examples/mock_example/config/plugins.yml +3 -0
- data/examples/sequel_example/README.txt +9 -0
- data/examples/sequel_example/application.rb +5 -0
- data/examples/sequel_example/config/database.yml +9 -0
- data/examples/sequel_example/config/framework.rb +5 -0
- data/examples/sequel_example/config/init.rb +24 -0
- data/examples/sequel_example/config/plugins.yml +3 -0
- data/examples/yaml_example/README.txt +9 -0
- data/examples/yaml_example/application.rb +5 -0
- data/examples/yaml_example/config/framework.rb +5 -0
- data/examples/yaml_example/config/init.rb +24 -0
- data/examples/yaml_example/config/plugins.yml +4 -0
- data/examples/yaml_example/locale/en.yaml +2 -0
- data/examples/yaml_example/locale/pl.yaml +2 -0
- data/lib/merb_global/base.rb +105 -0
- data/lib/merb_global/config.rb +36 -0
- data/lib/merb_global/controller.rb +38 -0
- data/lib/merb_global/date_providers/fork.rb +35 -0
- data/lib/merb_global/date_providers.rb +47 -0
- data/lib/merb_global/locale.rb +139 -0
- data/lib/merb_global/merbrake.rb +37 -0
- data/lib/merb_global/message_providers/active_record.rb +113 -0
- data/lib/merb_global/message_providers/data_mapper.rb +113 -0
- data/lib/merb_global/message_providers/gettext.rb +123 -0
- data/lib/merb_global/message_providers/gettext.treetop +60 -0
- data/lib/merb_global/message_providers/mock.rb +17 -0
- data/lib/merb_global/message_providers/sequel.rb +99 -0
- data/lib/merb_global/message_providers/yaml.rb +92 -0
- data/lib/merb_global/message_providers.rb +146 -0
- data/lib/merb_global/numeric_providers/fork.rb +35 -0
- data/lib/merb_global/numeric_providers/java.rb +15 -0
- data/lib/merb_global/numeric_providers.rb +48 -0
- data/lib/merb_global/plural.rb +20 -0
- data/lib/merb_global/plural.treetop +267 -0
- data/lib/merb_global/providers.rb +40 -0
- data/lib/merb_global.rb +8 -0
- data/sequel_generators/translations_migration/USAGE +4 -0
- data/sequel_generators/translations_migration/templates/translations_migration.erb +28 -0
- data/sequel_generators/translations_migration/translations_migration_generator.rb +32 -0
- metadata +92 -1
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'merb_global/base'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
class Controller
|
5
|
+
include Merb::Global
|
6
|
+
|
7
|
+
class_inheritable_accessor :_mg_locale
|
8
|
+
|
9
|
+
before do
|
10
|
+
# Set up the language
|
11
|
+
accept_language = self.request.env['HTTP_ACCEPT_LANGUAGE']
|
12
|
+
Merb::Global::Locale.current =
|
13
|
+
Merb::Global::Locale.new(params[:locale]) ||
|
14
|
+
(self._mg_locale &&
|
15
|
+
Merb::Global::Locale.new(self.instance_eval(&self._mg_locale))) ||
|
16
|
+
Merb::Global::Locale.from_accept_language(accept_language) ||
|
17
|
+
Merb::Global::Locale.new('en')
|
18
|
+
end
|
19
|
+
|
20
|
+
# Sets the language of block.
|
21
|
+
#
|
22
|
+
# The block should return language or nil if other method should be used
|
23
|
+
# to determine the language
|
24
|
+
#
|
25
|
+
# Please note that this method is deprecated and the preferred method is
|
26
|
+
# locale.
|
27
|
+
def self.language(&block)
|
28
|
+
self._mg_locale = block
|
29
|
+
end
|
30
|
+
# Sets the language of block.
|
31
|
+
#
|
32
|
+
# The block should return language or nil if other method should be used
|
33
|
+
# to determine the language
|
34
|
+
def self.locale(&block)
|
35
|
+
self._mg_locale = block
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'inline'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
module Global
|
5
|
+
module DateProviders
|
6
|
+
class Fork
|
7
|
+
include Merb::Global::DateProviders::Base
|
8
|
+
|
9
|
+
def localize(lang, date, format)
|
10
|
+
pipe_rd, pipe_wr = IO.pipe
|
11
|
+
pid = fork do
|
12
|
+
pipe_rd.close
|
13
|
+
setlocale(lang.to_s)
|
14
|
+
pipe_wr.write(date.strftime(format))
|
15
|
+
pipe_wr.flush
|
16
|
+
end
|
17
|
+
pipe_wr.close
|
18
|
+
Process.wait(pid)
|
19
|
+
pipe_rd.read
|
20
|
+
end
|
21
|
+
|
22
|
+
inline do |builder|
|
23
|
+
builder.include '<locale.h>'
|
24
|
+
builder.c <<C
|
25
|
+
void set_locale(const char *locale)
|
26
|
+
{
|
27
|
+
setlocale(LC_ALL, locale);
|
28
|
+
}
|
29
|
+
C
|
30
|
+
end
|
31
|
+
private :set_locale
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'merb_global/providers'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
module Global
|
5
|
+
module DateProviders
|
6
|
+
include Providers
|
7
|
+
# call-seq:
|
8
|
+
# provider => provider
|
9
|
+
#
|
10
|
+
# Returns the provider of required type
|
11
|
+
#
|
12
|
+
# ==== Returns
|
13
|
+
# provider<Provider>:: Returns provider
|
14
|
+
def self.provider
|
15
|
+
@@provider ||= self[Merb::Global.config(:date_provider, 'fork')]
|
16
|
+
end
|
17
|
+
# Merb-global is able to handle localization in different ways.
|
18
|
+
# Providers are the interface.
|
19
|
+
#
|
20
|
+
# Please note that it is not required to include this module - despite it
|
21
|
+
# is recomended both as a documentation part and the more customized
|
22
|
+
# error messages.
|
23
|
+
module Base
|
24
|
+
##
|
25
|
+
#
|
26
|
+
# Localize date using format as in strftime
|
27
|
+
def localize(lang, date, format)
|
28
|
+
raise NoMethodError.new('method localize has not been implemented')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
# Perform the registration
|
33
|
+
#
|
34
|
+
# ==== Parameters
|
35
|
+
# name<~to_sym>:: Name under which it is registered
|
36
|
+
def self.DateProvider(provider_name)
|
37
|
+
Module.new do
|
38
|
+
@@rb_date_provider_name = provider_name
|
39
|
+
include Merb::Global::DateProviders::Base
|
40
|
+
|
41
|
+
def self.included(klass)
|
42
|
+
Merb::Global::DateProviders.register @@rb_date_provider_name, klass
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'merb_global/base'
|
2
|
+
require 'thread'
|
3
|
+
require 'weakref'
|
4
|
+
|
5
|
+
class Thread
|
6
|
+
attr_accessor :mg_locale
|
7
|
+
end
|
8
|
+
|
9
|
+
module Merb
|
10
|
+
module Global
|
11
|
+
class Locale
|
12
|
+
attr_reader :language, :country
|
13
|
+
|
14
|
+
def initialize(name)
|
15
|
+
# TODO: Understand RFC 1766 fully
|
16
|
+
@language, @country = name.split('-')
|
17
|
+
end
|
18
|
+
|
19
|
+
def any?
|
20
|
+
language == '*' && country.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_locale
|
24
|
+
if not @country.nil?
|
25
|
+
Locale.new(@language)
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
if country.nil?
|
33
|
+
"#{@language.downcase}"
|
34
|
+
else
|
35
|
+
"#{@language.downcase}_#{@country.upcase}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if defined? RUBY_ENGINE and RUBY_ENGINE == "jruby"
|
40
|
+
def java_locale
|
41
|
+
require 'java'
|
42
|
+
@java_locale ||=
|
43
|
+
if @country.nil?
|
44
|
+
java.util.Locale.new(@language.downcase)
|
45
|
+
else
|
46
|
+
java.util.Locale.new(@language.downcase, @country.upcase)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
def java_locale
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.parse(header)
|
56
|
+
header = header.split(',')
|
57
|
+
header.collect! {|lang| lang.delete ' ' "\n" "\r" "\t"}
|
58
|
+
header.reject! {|lang| lang.empty?}
|
59
|
+
header.collect! {|lang| lang.split ';q='}
|
60
|
+
header.collect! do |lang|
|
61
|
+
if lang.size == 1
|
62
|
+
[lang[0], 1.0]
|
63
|
+
else
|
64
|
+
[lang[0], lang[1].to_f]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
header.sort! {|lang_a, lang_b| lang_b[1] <=> lang_a[1]} # sorting by decreasing quality
|
68
|
+
header.collect! {|lang| Locale.new(lang[0])}
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.from_accept_language(accept_language)
|
72
|
+
unless accept_language.nil?
|
73
|
+
accept_language = Merb::Global::Locale.parse(accept_language)
|
74
|
+
accept_language.each_with_index do |lang, i|
|
75
|
+
if lang.any?
|
76
|
+
# In this case we need to choose a locale that is not in accept_language[i+1..-1]
|
77
|
+
return Merb::Global::Locale.choose(accept_language[i+1..-1])
|
78
|
+
elsif Merb::Global::Locale.support? lang
|
79
|
+
return lang
|
80
|
+
end
|
81
|
+
lang = lang.base_locale
|
82
|
+
return lang if lang && Merb::Global::Locale.support?(lang)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.current
|
88
|
+
Thread.current.mg_locale
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.current=(new_locale)
|
92
|
+
Thread.current.mg_locale = new_locale
|
93
|
+
end
|
94
|
+
|
95
|
+
class << self
|
96
|
+
alias_method :pure_new, :new
|
97
|
+
private :pure_new
|
98
|
+
end
|
99
|
+
|
100
|
+
@@current = {}
|
101
|
+
@@current_mutex = Mutex.new
|
102
|
+
# Create new locale object and returns it.
|
103
|
+
#
|
104
|
+
# Please note that this method is cached.
|
105
|
+
def self.new(name)
|
106
|
+
return nil if name.nil?
|
107
|
+
return name if name.is_a? Locale
|
108
|
+
@@current_mutex.synchronize do
|
109
|
+
begin
|
110
|
+
n = @@current[name]
|
111
|
+
if n.nil?
|
112
|
+
n = pure_new(name)
|
113
|
+
@@current[name] = WeakRef.new(n)
|
114
|
+
else
|
115
|
+
n = n.__getobj__
|
116
|
+
end
|
117
|
+
n
|
118
|
+
rescue WeakRef::RefError
|
119
|
+
n = pure_new(name)
|
120
|
+
@@current[name] = WeakRef.new(n)
|
121
|
+
n
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.support?(locale)
|
127
|
+
supported_locales.include? locale.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.supported_locales
|
131
|
+
Merb::Global::config('locales', ['en'])
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.choose(except)
|
135
|
+
new((supported_locales - except.map{|e| e.to_s}).first)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
namespace :merb_global do
|
4
|
+
|
5
|
+
task :merb_start do
|
6
|
+
Merb.start_environment :adapter => 'runner',
|
7
|
+
:environment => ENV['MERB_ENV'] || 'development'
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Create migration'
|
11
|
+
task :migration => :merb_start do
|
12
|
+
Merb::Global::MessageProviders.provider.create!
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Transfer the translations from one provider to another'
|
16
|
+
task :transfer => :merb_start do
|
17
|
+
from = Merb::Global.config 'source', 'gettext'
|
18
|
+
into = Merb::Global.config 'provider', 'gettext'
|
19
|
+
if from == 'gettext' and into == 'gettext'
|
20
|
+
Dir[Merb::Global::MessageProviders.localedir + '/*.po'].each do |file|
|
21
|
+
lang = File.basename file, '.po'
|
22
|
+
lang_dir = File.join(Merb::Global::MessageProviders.localedir,
|
23
|
+
lang, 'LC_MESSAGES')
|
24
|
+
FileUtils.mkdir_p lang_dir
|
25
|
+
domain = Merb::Global.config([:gettext, :domain], 'merbapp')
|
26
|
+
`msgfmt #{file} -o #{lang_dir}/#{domain}.mo`
|
27
|
+
end
|
28
|
+
elsif from == into
|
29
|
+
Merb.logger.error 'Tried transfer from and into the same provider'
|
30
|
+
else
|
31
|
+
from = Merb::Global::MessageProviders[from]
|
32
|
+
into = Merb::Global::MessageProviders[into]
|
33
|
+
Merb::Global::Provider.transfer from, into
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'activerecord'
|
2
|
+
# As far as I understand, we need it to have composite keys.
|
3
|
+
# However it may be better idea to drop them.
|
4
|
+
# So far I implement it in this way - then we will see
|
5
|
+
require 'composite_primary_keys' # As far as I understand we need
|
6
|
+
require 'merb_global/plural'
|
7
|
+
|
8
|
+
module Merb
|
9
|
+
module Global
|
10
|
+
module MessageProviders
|
11
|
+
class ActiveRecord #:nodoc: all
|
12
|
+
include Merb::Global::MessageProviders::Base
|
13
|
+
include Merb::Global::MessageProviders::Base::Importer
|
14
|
+
include Merb::Global::MessageProviders::Base::Exporter
|
15
|
+
|
16
|
+
def localize(singular, plural, n, locale)
|
17
|
+
language = Language.find :first,
|
18
|
+
:conditions => {:name => locale.to_s}
|
19
|
+
unless language.nil?
|
20
|
+
unless plural.nil?
|
21
|
+
pn = Plural.which_form n, language.plural
|
22
|
+
translation = Translation.find [language.id, singular, pn]
|
23
|
+
else
|
24
|
+
# Bug of composite_primary_keys?
|
25
|
+
conditions = {
|
26
|
+
:language_id => language.id,
|
27
|
+
:msgid => singular,
|
28
|
+
:msgstr_index => nil
|
29
|
+
}
|
30
|
+
translation = Translation.find(:first, conditions)
|
31
|
+
end
|
32
|
+
return translation.msgstr
|
33
|
+
end rescue nil
|
34
|
+
return n > 1 ? plural : singular # Fallback if not in database
|
35
|
+
end
|
36
|
+
|
37
|
+
def create!
|
38
|
+
migration_exists = Dir[File.join(Merb.root, 'schema',
|
39
|
+
'migrations', '*.rb')].detect do |f|
|
40
|
+
f =~ /translations\.rb/
|
41
|
+
end
|
42
|
+
if migration_exists
|
43
|
+
puts "\nThe Translation Migration File already exists\n\n"
|
44
|
+
else
|
45
|
+
sh %{merb-gen translations_migration}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def import
|
50
|
+
data = {}
|
51
|
+
Language.transaction do
|
52
|
+
Translation.transaction do
|
53
|
+
Language.find(:all).each do |lang|
|
54
|
+
data[lang.name] = lang_hash = {
|
55
|
+
:plural => lang.plural,
|
56
|
+
:nplural => lang.nplural
|
57
|
+
}
|
58
|
+
lang.translations.each do |translation|
|
59
|
+
lang_hash[translation.msgid] ||= {
|
60
|
+
:plural => translation.msgid_plural
|
61
|
+
}
|
62
|
+
lang_hash[translation.msgid][translation.msgstr_index] =
|
63
|
+
translation.msgstr
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
data
|
69
|
+
end
|
70
|
+
|
71
|
+
def export(data)
|
72
|
+
Language.transaction do
|
73
|
+
Translation.transaction do
|
74
|
+
Translation.delete_all
|
75
|
+
Language.delete_all
|
76
|
+
data.each do |lang_name, lang|
|
77
|
+
lang_id = Language.create!(:name => lang_name,
|
78
|
+
:plural => lang[:plural],
|
79
|
+
:nplural => lang[:nplural]).id
|
80
|
+
lang.each do |msgid, msgstrs|
|
81
|
+
if msgid.is_a? String
|
82
|
+
plural = msgstrs[:plural]
|
83
|
+
msgstrs.each do |index, msgstr|
|
84
|
+
if index.nil? or index.is_a? Fixnum
|
85
|
+
Translation.create! :language_id => lang_id,
|
86
|
+
:msgid => msgid,
|
87
|
+
:msgid_plural => plural,
|
88
|
+
:msgstr => msgstr,
|
89
|
+
:msgstr_index => index
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class Language < ::ActiveRecord::Base
|
100
|
+
set_table_name :merb_global_languages
|
101
|
+
has_many :translations,
|
102
|
+
:class_name =>
|
103
|
+
"::Merb::Global::MessageProviders::ActiveRecord::Translation"
|
104
|
+
end
|
105
|
+
|
106
|
+
class Translation < ::ActiveRecord::Base
|
107
|
+
set_table_name :merb_global_translations
|
108
|
+
set_primary_keys :language_id, :msgid, :msgstr_index
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'dm-aggregates'
|
3
|
+
require 'merb_global/plural'
|
4
|
+
|
5
|
+
module Merb
|
6
|
+
module Global
|
7
|
+
module MessageProviders
|
8
|
+
class DataMapper #:nodoc: all
|
9
|
+
include Merb::Global::MessageProviders
|
10
|
+
include Merb::Global::MessageProviders::Base::Importer
|
11
|
+
include Merb::Global::MessageProviders::Base::Exporter
|
12
|
+
|
13
|
+
def localize(singular, plural, n, locale)
|
14
|
+
# I hope it's from MemCache
|
15
|
+
language = Language.first :name => locale.to_s
|
16
|
+
unless language.nil?
|
17
|
+
unless plural.nil?
|
18
|
+
pn = Plural.which_form n, language.plural
|
19
|
+
translation = Translation.first :language_id => language.id,
|
20
|
+
:msgid => singular,
|
21
|
+
:msgstr_index => pn
|
22
|
+
else
|
23
|
+
translation = Translation.first :language_id => language.id,
|
24
|
+
:msgid => singular,
|
25
|
+
:msgstr_index => nil
|
26
|
+
end
|
27
|
+
return translation.msgstr unless translation.nil?
|
28
|
+
end
|
29
|
+
# Fallback if not in database
|
30
|
+
return n != 1 ? plural : singular
|
31
|
+
end
|
32
|
+
|
33
|
+
def create!
|
34
|
+
Language.auto_migrate!
|
35
|
+
Translation.auto_migrate!
|
36
|
+
end
|
37
|
+
|
38
|
+
def import
|
39
|
+
data = {}
|
40
|
+
::DataMapper::Transaction.new(Language, Translation) do
|
41
|
+
Language.all.each do |language|
|
42
|
+
data[language.name] = lang_hash = {
|
43
|
+
:plural => language.plural,
|
44
|
+
:nplural => language.nplural
|
45
|
+
}
|
46
|
+
language.translations(:fields => Translation.properties.to_a).
|
47
|
+
each do |translation|
|
48
|
+
lang_hash[translation.msgid] ||= {
|
49
|
+
:plural => translation.msgid_plural
|
50
|
+
}
|
51
|
+
lang_hash[translation.msgid][translation.msgstr_index] =
|
52
|
+
translation.msgstr
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
data
|
57
|
+
end
|
58
|
+
|
59
|
+
def export(data)
|
60
|
+
::DataMapper::Transaction.new(Language, Translation) do
|
61
|
+
Translation.all.each {|translation| translation.destroy}
|
62
|
+
Language.all.each {|language| language.destroy}
|
63
|
+
data.each do |lang_name, lang|
|
64
|
+
lang_obj = Language.create!(:name => lang_name,
|
65
|
+
:plural => lang[:plural],
|
66
|
+
:nplural => lang[:nplural])
|
67
|
+
lang.each do |msgid, msgstr_hash|
|
68
|
+
if msgstr_hash.is_a? Hash
|
69
|
+
plural = msgstr_hash[:plural]
|
70
|
+
msgstr_hash.each do |msgstr_index, msgstr|
|
71
|
+
if msgstr_index.nil? or msgstr_index.is_a? Fixnum
|
72
|
+
Translation.create!(:language_id => lang_obj.id,
|
73
|
+
:msgid => msgid,
|
74
|
+
:msgid_plural => plural,
|
75
|
+
:msgstr => msgstr,
|
76
|
+
:msgstr_index => msgstr_index) or
|
77
|
+
raise
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# When table structure becomes stable it *should* be documented
|
87
|
+
class Language
|
88
|
+
include ::DataMapper::Resource
|
89
|
+
storage_names[:default] = 'merb_global_languages'
|
90
|
+
property :id, Integer, :serial => true
|
91
|
+
property :name, String, :unique_index => true
|
92
|
+
property :nplural, Integer
|
93
|
+
property :plural, Text, :lazy => false
|
94
|
+
# validates_is_unique :name
|
95
|
+
has n, :translations,
|
96
|
+
:class_name => "Merb::Global::MessageProviders::DataMapper::Translation",
|
97
|
+
:child_key => [:language_id]
|
98
|
+
end
|
99
|
+
|
100
|
+
class Translation
|
101
|
+
include ::DataMapper::Resource
|
102
|
+
storage_names[:default] = 'merb_global_translations'
|
103
|
+
property :language_id, Integer, :nullable => false, :key => true
|
104
|
+
property :msgid, Text, :nullable => false, :key => true
|
105
|
+
property :msgid_plural, Text, :lazy => true
|
106
|
+
property :msgstr, Text, :nullable => false, :lazy => false
|
107
|
+
property :msgstr_index, Integer, :nullable => true, :key => true
|
108
|
+
belongs_to :language, :class_name => Language.name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'gettext'
|
2
|
+
require 'treetop'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
class Merb::Global::Locale #:nodoc:
|
6
|
+
def _mg_gettext
|
7
|
+
@mg_gettext ||= Merb::Global::MessageProviders::Gettext::GettextContext.new
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Merb
|
12
|
+
module Global
|
13
|
+
module MessageProviders
|
14
|
+
class Gettext #:nodoc: all
|
15
|
+
include Merb::Global::MessageProviders::Base
|
16
|
+
include Merb::Global::MessageProviders::Base::Importer
|
17
|
+
include Merb::Global::MessageProviders::Base::Exporter
|
18
|
+
|
19
|
+
def localize(singular, plural, n, locale)
|
20
|
+
context = locale._mg_gettext
|
21
|
+
context.set_locale locale.to_s, true
|
22
|
+
unless plural.nil?
|
23
|
+
context.ngettext singular, plural, n
|
24
|
+
else
|
25
|
+
context.gettext singular
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def create!
|
30
|
+
File.mkdirs Merb::Global::MessageProviders.localedir
|
31
|
+
end
|
32
|
+
|
33
|
+
def import
|
34
|
+
Treetop.load(Pathname(__FILE__).dirname.expand_path.to_s +
|
35
|
+
'/gettext')
|
36
|
+
parser = Merb::Global::MessageProviders::GetTextParser.new
|
37
|
+
data = {}
|
38
|
+
Dir[Merb::Global::MessageProviders.localedir +
|
39
|
+
'/*.po'].each do |file|
|
40
|
+
lang_name = File.basename file, '.po'
|
41
|
+
lang_tree = nil
|
42
|
+
open file do |f|
|
43
|
+
lang_tree = parser.parse f.read
|
44
|
+
end
|
45
|
+
# Put the parsed file in data
|
46
|
+
data[lang_name] = lang_tree.to_hash
|
47
|
+
# Remove the metadata to futher managing
|
48
|
+
opts = data[lang_name].delete('')[nil].split("\n")
|
49
|
+
# Find the line about plural line
|
50
|
+
plural_line = nil
|
51
|
+
for l in opts
|
52
|
+
if l[0..."Plural-Forms:".length] == "Plural-Forms:"
|
53
|
+
plural_line = l
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# Remove the "Plural-Forms:" from the beginning...
|
58
|
+
plural_line =
|
59
|
+
plural_line["Plural-Forms:".length...plural_line.length]
|
60
|
+
# and ; from end
|
61
|
+
plural_line = plural_line[0...plural_line.length-1]
|
62
|
+
# Split the line and build the hash
|
63
|
+
plural_line = plural_line.gsub(/[[:space:]]/, '').split(/[=;]/, 4)
|
64
|
+
# And change the plural and nplurals into :plural and :nplurals
|
65
|
+
plural_line[2] = :plural
|
66
|
+
plural_line[0] = :nplural
|
67
|
+
# Adn the nplural value into integer
|
68
|
+
plural_line[1] = plural_line[1].to_i
|
69
|
+
data[lang_name].merge! Hash[*plural_line]
|
70
|
+
end
|
71
|
+
data
|
72
|
+
end
|
73
|
+
|
74
|
+
def export(data)
|
75
|
+
data.each do |lang_name, lang|
|
76
|
+
lang_file = File.join(Merb::Global::MessageProviders.localedir,
|
77
|
+
lang_name + '.po')
|
78
|
+
open(lang_file, 'w') do |po|
|
79
|
+
po.puts <<EOF
|
80
|
+
msgid ""
|
81
|
+
msgstr ""
|
82
|
+
"Project-Id-Version: 0.0.1\\n"
|
83
|
+
"POT-Creation-Date: #{Time.now.strftime('%Y-%m-%d %H:%M%z')}\\n"
|
84
|
+
"PO-Revision-Date: #{Time.now.strftime('%Y-%m-%d %H:%M%z')}\\n"
|
85
|
+
"Last-Translator: <user@example.com>\\n"
|
86
|
+
"Language-Team: Language type\\n"
|
87
|
+
"MIME-Version: 1.0\\n"
|
88
|
+
"Content-Type: text/plain; charset=UTF-8\\n"
|
89
|
+
"Content-Transfer-Encoding: 8bit\\n"
|
90
|
+
"Plural-Forms: nplurals=#{lang[:nplurals]}; plural=#{lang[:plural]}\\n"
|
91
|
+
EOF
|
92
|
+
|
93
|
+
lang.each do |msgid, msgstr_hash|
|
94
|
+
po.puts ""
|
95
|
+
po.puts "msgid \"#{msgid}\""
|
96
|
+
if msgstr_hash[:plural]
|
97
|
+
po.puts "msgid_plural \"#{msgstr_hash[:plural]}\""
|
98
|
+
msgstr_hash.each do |msgstr_index, msgstr|
|
99
|
+
po.puts "msgstr[#{msgstr_index}] \"#{msgstr}\""
|
100
|
+
end
|
101
|
+
else
|
102
|
+
po.puts "msgstr \"#{msgstr_hash[nil]}\""
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
lang_dir = File.join(Merb::Global::MessageProviders.localedir,
|
107
|
+
lang, 'LC_MESSAGES')
|
108
|
+
FileUtils.mkdir_p lang_dir
|
109
|
+
domain = Merb::Global.config([:gettext, :domain], 'merbapp')
|
110
|
+
`msgfmt #{lang_file} -o #{lang_dir}/#{domain}.mo`
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class GettextContext
|
115
|
+
include ::GetText
|
116
|
+
bindtextdomain Merb::Global.config([:gettext, :domain], 'merbapp'),
|
117
|
+
Merb::Global::MessageProviders.localedir
|
118
|
+
public :set_locale, :ngettext, :gettext
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|