lastobelus-merb_global 0.0.7 → 0.0.8
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.
- 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
|