merb_babel 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Matt Aimonetti
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,151 @@
1
+ Merb_babel
2
+ =========
3
+
4
+ A plugin for the Merb framework that provides locales, languages, countries. (in a thread safe environment)
5
+
6
+
7
+ Purpose of Merb\_babel
8
+ ---------------------
9
+
10
+ Merb_babel is primarily written to fulfill my personal needs. Instead of porting my http://github.com/mattetti/globalite plugin over, I decided to re write it from scratch learning from my mistakes.
11
+
12
+ Goals:
13
+
14
+ * simplicity
15
+ * speed
16
+
17
+ My first and simple objective is to get Merb to work in Simplified and Traditional Chinese + switch from one to the other.
18
+
19
+ Also, as of today, I'm not planning on supporting model localization since I believe it's easy to do, and in most cases it's too specific to use a plugin. (but other plugins offer that for you anyway ;) )
20
+
21
+ One of the objectives is that people can add Merb\_babel to their project and use merb in a different language without worrying about internationalization/localization. I hope to keep merb helpers and other plugins (merb\_activerecord / merb\_datamapper / merb\_sequel) localized so someone can define his app's locale/language/country and Merb will talk his language right away.
22
+
23
+ Before you go further, you might want to read [this explanation about i18n/l10n](http://www.w3.org/International/questions/qa-i18n)
24
+
25
+ Usage
26
+ ------
27
+
28
+ In your application controller add:
29
+
30
+ before :set_locale
31
+
32
+
33
+ and access the user locale using @controller.locale (or simply #locale in the controller)
34
+ If a locale is set, you can also access @controller.language and @controller.country (same thing, you can use #language or #country from within your controller scope)
35
+
36
+ The locale is stored in request.env[:locale]
37
+
38
+ At the moment you have 3 ways of setting up a locale:
39
+
40
+ * default way in the config settings (that you can overwrite in your init.rb file )
41
+
42
+ Merb::Plugins.config[:Merb_babel] = {
43
+ :default_locale => 'en-US',
44
+ :default_language => 'en',
45
+ :default_country => 'US'
46
+ }
47
+
48
+ * per request basis, by sending a param called locale (language, and country will set their own values)
49
+ * store the locale in the session
50
+ * use routes
51
+
52
+ Babel doesn't support http header lookup yet.
53
+
54
+ Set locale in your routes
55
+ --------------------------
56
+
57
+ r.match(/\/?(en\-US|en\-UK|es\-ES|es\-AR)?/).to(:locale => "[1]") do |l|
58
+ l.match("/articles/:action/:id").to(:controller => "articles")
59
+ end
60
+
61
+ What if you don't need to use a full locale?
62
+ --------------------------------------------
63
+
64
+ some people might not need to use the full locale, they just want to use one version of a language and the locale is an overkill. Don't worry, you can use the language instance variable.
65
+
66
+ before :set_language
67
+
68
+
69
+ All locale work is done in ``merb_babel/lib/merb_babel/m_locale.rb`` and tested in ``spec/merb_babel_spec.rb``
70
+
71
+ Localization(L10n)
72
+ ------------------
73
+
74
+ L10n is basically the adaptation of your product to a specific locale. In our case, we see L10n as the storing and retrieval of localized data. (for a locale or language)
75
+
76
+ Localizations are loaded from localization files.
77
+
78
+ Localization files are simple yaml files that get loaded in memory. By default Merb\_babel will look in ./lang for localization files. The default location is defined in Merb::Plugins.config[:merb_babel][:localization_dirs] and can be overwritten. Also, you can add more folders to look for by calling:
79
+
80
+ add_localization_dir(path_with_more_localization_files)
81
+
82
+ Note: when you add a new localization directory, localizations gets reloaded.
83
+ This needs to be done when Merb loads as I didn't add a mutex around that task yet.
84
+
85
+ Localizations are available in #localizations and are namespaced as follows:
86
+
87
+ localizations['en'][:right] => 'right'
88
+ localizations['en'][:left] => 'left'
89
+ localizations['en']['US'][:greeting] => 'Howdie'
90
+ localizations['en']['AU'][:greeting] => "Good'ay"
91
+
92
+ For that the localization files to be loaded properly, you need to follow some conventions:
93
+
94
+ * you have to declare a merb localization language code pair:
95
+ mloc\_language_code: en
96
+ where en represents the language code of the localization
97
+
98
+ * All generic localization for a language should go under their own language file. Region/culture specific localizations have to go to their own files and will be used if the full locale is set.
99
+
100
+ * A localization file is recognized as being locale specific if the mloc_country_code pair is set.
101
+
102
+ * ONLY localizations/translations specific to a locale should be written in a locale file.
103
+
104
+ * Recommended: set the mloc\_language_name pair so you list the available languages in their own language.
105
+
106
+ * look at examples in spec/lang
107
+
108
+ All the Localization(L10n) work is done in ``merb_babel/lib/merb_abel/m_l10n.rb`` and tested in ``spec/m_l10n_spec.rb``
109
+
110
+
111
+ Internationalization(I18n)
112
+ --------------------------
113
+
114
+ I18n enables easy localization of your product. That's what the developer/designer user to make their data localizable.
115
+
116
+ At the moment, only strings can be localized/translated.
117
+
118
+ In your controller, or view simply do:
119
+
120
+ translate(:localization_key)
121
+
122
+ You might prefer a shorter version so here are some aliases for you to use:
123
+
124
+ babelize(:translation_key)
125
+ or
126
+ t(:translation_key)
127
+ or
128
+ _(:translation_key)
129
+
130
+ The translation will use the full locale (language and country) if set and available, otherwise the language translation will be displayed.
131
+
132
+ *Params*
133
+
134
+ You can pass a hash of parameters after the translation key. For instance:
135
+
136
+ t(:greetings, :language => 'fr')
137
+
138
+ Would lookup the French translation for the greetings key and return 'Salut'
139
+
140
+ You can also pass the country code to use the full locale.
141
+
142
+ t(:greetings, :language => 'en', :country => 'AU')
143
+
144
+ would lookup the Australian English translation for the greetings key and return "G'day"
145
+
146
+
147
+ Other plugins you might want to look at:
148
+ ----------------------------------------
149
+
150
+ * http://github.com/myabc/merb_global
151
+ * http://github.com/lemon/poppycock
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ require 'merb-core'
5
+ require 'merb-core/tasks/merb'
6
+
7
+ GEM_NAME = "merb_babel"
8
+ GEM_VERSION = "0.1.2"
9
+ AUTHOR = "Matt Aimonetti"
10
+ EMAIL = "mattaimonetti@gmail.com"
11
+ HOMEPAGE = "http://github.com/mattetti/merb_babel/"
12
+ SUMMARY = "Merb plugin that provides simple localization/internationalisation"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.rubyforge_project = 'merb'
16
+ s.name = GEM_NAME
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", 'TODO']
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+ s.add_dependency('merb-core', '>= 1.0')
27
+ s.add_dependency('locale', '>= 0.9.0')
28
+ s.require_path = 'lib'
29
+ s.files = %w(LICENSE README.markdown Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.gem_spec = spec
34
+ end
35
+
36
+ desc "install the plugin as a gem"
37
+ task :install do
38
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
39
+ end
40
+
41
+ desc "Uninstall the gem"
42
+ task :uninstall do
43
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
44
+ end
45
+
46
+ desc "Create a gemspec file"
47
+ task :gemspec do
48
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
49
+ file.puts spec.to_ruby
50
+ end
51
+ end
52
+
53
+ desc "Run specs"
54
+ task :spec do
55
+ sh "spec --color spec"
56
+ end
57
+
58
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/merb_abel.rb
5
+ Add your Merb rake tasks to lib/merb_abel/merbtasks.rb
@@ -0,0 +1,59 @@
1
+ #require File.join(File.dirname(__FILE__) / "merb_babel" / "core_ext")
2
+
3
+ # make sure we're running inside Merb
4
+ if defined?(Merb::Plugins)
5
+
6
+ # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
7
+ Merb::Plugins.config[:merb_babel] = {
8
+ :default_locale => 'en-US',
9
+ :default_language => 'en',
10
+ # :default_country => 'US',
11
+ :localization_dirs => ["#{Merb.root}/lang"]
12
+ }
13
+
14
+ require File.join(File.dirname(__FILE__) / "merb_babel" / "m_locale")
15
+ require File.join(File.dirname(__FILE__) / "merb_babel" / "m_l10n")
16
+ require File.join(File.dirname(__FILE__) / "merb_babel" / "m_i18n")
17
+ require File.join(File.dirname(__FILE__) / "merb_babel" / 'locale_detector')
18
+ gem "locale"
19
+ require 'locale'
20
+
21
+ Merb::BootLoader.before_app_loads do
22
+ # require code that must be loaded before the application
23
+ module Merb
24
+ module GlobalHelpers
25
+
26
+ # Used to translate words using localizations
27
+ def babelize(*args)
28
+ begin
29
+ options = args.pop if args.last.kind_of?(Hash)
30
+ options ||= {}
31
+ options[:language] ||= language
32
+ options[:country] ||= country
33
+ case key = args.last
34
+ when Date, Time
35
+ format = MI18n.lookup(options.merge(:keys => args[0..-2]))
36
+ ML10n.localize_time(key, format, options)
37
+ else
38
+ MI18n.lookup(options.merge(:keys => args))
39
+ end
40
+ rescue
41
+ key.to_s
42
+ end
43
+ end
44
+ alias :translate :babelize
45
+ alias :t :babelize
46
+ alias :_ :babelize
47
+ end
48
+ end
49
+
50
+ Merb::Controller.send(:include, MLocale)
51
+ ML10n.load_localization!
52
+ end
53
+
54
+ Merb::BootLoader.after_app_loads do
55
+ # code that can be required after the application loads
56
+ end
57
+
58
+ Merb::Plugins.add_rakefiles "merb_babel/merbtasks"
59
+ end
@@ -0,0 +1,80 @@
1
+ module LocaleDetector
2
+ LANGUAGE_TO_COUNTRY = {
3
+ "nn"=>["NO"],
4
+ "uk"=>["UA"],
5
+ "it"=>["IT", "GI", "CH", "LY", "SM"],
6
+ "zh_TW"=>["TT", "VN", "HK"],
7
+ "no"=>["NO"],
8
+ "st"=>["ZA"],
9
+ "tk"=>["TM"],
10
+ "bn"=>["IN"],
11
+ "mn"=>["MN"],
12
+ "ja"=>["JP"],
13
+ "fr"=>["FR", "CD", "GG", "RW", "CG", "LU", "TT", "CH", "CI", "JE", "SC",
14
+ "VN", "BE", "MU", "DJ", "BI", "CA"],
15
+ "hi"=>["TT", "AE", "IN"],
16
+ "de"=>["DE", "LU", "CH", "LI", "AT", "BE", "RO"],
17
+ "ne"=>["NP"], "jw"=>["ID"],
18
+ "ta"=>["IN", "SG"],
19
+ "tl"=>["PH"],
20
+ "pt_PT"=>["PT", "GI"],
21
+ "hu"=>["HU", "SK", "RO"],
22
+ "sk"=>["SK"],
23
+ "fi"=>["FI"],
24
+ "sv"=>["SE", "FI"],
25
+ "iw"=>["IL"],
26
+ "az"=>["AZ"],
27
+ "zh"=>["TW"],
28
+ "ru"=>["RU", "KZ", "KG", "AZ", "LV", "UA", "TM", "AM", "UZ"],
29
+ "ky"=>["KG"],
30
+ "es"=>["ES", "HN", "CU", "PR", "TT", "PA", "VE", "DO", "BO", "GI", "PE",
31
+ "PY", "NI", "CL", "SV", "CO", "UY", "BZ", "CR", "EC", "GT", "AR", "MX"],
32
+ "ko"=>["KR"],
33
+ "pt_BR"=>["BR"],
34
+ "sw"=>["RW", "KE"],
35
+ "ga"=>["IE"],
36
+ "id"=>["ID"],
37
+ "eu"=>["ES"],
38
+ "gl"=>["ES"],
39
+ "xh"=>["ZA"],
40
+ "uz"=>["TM", "UZ"],
41
+ "mr"=>["IN"],
42
+ "fa"=>["AE"],
43
+ "zu"=>["LS", "ZA"],
44
+ "af"=>["NA", "ZA"],
45
+ "pl"=>["PL"],
46
+ "hy"=>["AM"],
47
+ "pa"=>["PK"],
48
+ "te"=>["IN"],
49
+ "ar"=>["AE", "LY", "SA", "DJ"],
50
+ "ms"=>["MY", "SG"],
51
+ "el"=>["GR"],
52
+ "ro"=>["RO"],
53
+ "mt"=>["MT"],
54
+ "ur"=>["AE", "PK"],
55
+ "da"=>["DK", "GL"],
56
+ "ca"=>["ES"],
57
+ "tr"=>["TR"],
58
+ "zh_CN"=>["SG"],
59
+ "nl"=>["NL", "BE", "ID"],
60
+ "vi"=>["VN"],
61
+ "lt"=>["LT", "LV"],
62
+ "th"=>["TH"],
63
+ "fo"=>["DK"],
64
+ "en"=>["US", "AS", "IE", "NP", "MY", "UK", "FM", "VC", "PR", "TT", "AU",
65
+ "PA", "NA", "GG", "LS", "RW", "VG", "AE", "GI", "VI", "AG", "TH", "CH",
66
+ "NF", "JE", "AI", "GL", "PH", "CK", "GM", "LY", "IN", "NZ", "NI", "SC",
67
+ "PK", "VN", "MS", "TO", "MT", "BE", "PN", "MU", "UG", "SG", "ZA", "BZ",
68
+ "SH", "MW", "FJ", "CR", "HK", "JM", "KE", "CA", "ID"],
69
+ "lv"=>["LV"]
70
+ }.freeze
71
+
72
+ module_function
73
+ def countries_from_language(language)
74
+ LANGUAGE_TO_COUNTRY[language]
75
+ end
76
+
77
+ def country_from_language(language)
78
+ (countries_from_language(language) || []).first
79
+ end
80
+ end
@@ -0,0 +1,39 @@
1
+ module MI18n
2
+
3
+ def self.lookup(options)
4
+ keys = [options[:keys].map{|key| key.to_s}].flatten
5
+ language = options[:language]
6
+ country = options[:country]
7
+
8
+ raise ArgumentError, "You need to pass a language reference" unless language
9
+ raise ArgumentError, "You need to pass a localization key" if keys.empty?
10
+ raise ArgumentError,
11
+ "language: #{language} not found" unless ML10n.localizations[language]
12
+
13
+ full_location = nil
14
+ full_location = lookup_with_full_locale(keys, language, country) if country
15
+
16
+ if full_location
17
+ return full_location
18
+ else
19
+ return lookup_with_language(keys, language) || keys.last
20
+ end
21
+ end
22
+
23
+ def self.lookup_with_language(keys, language)
24
+ lookup_with_hash(keys, ML10n.localizations[language])
25
+ end
26
+
27
+ def self.lookup_with_full_locale(keys, language, country)
28
+ if ML10n.localizations.has_key?(language)
29
+ ML10n.localizations[language].has_key?(country) ?
30
+ lookup_with_hash(keys, ML10n.localizations[language][country]) : nil
31
+ else
32
+ nil
33
+ end
34
+ end
35
+
36
+ def self.lookup_with_hash(keys, l_hash)
37
+ keys.inject(l_hash){|h,k| h[k] rescue nil}
38
+ end
39
+ end
@@ -0,0 +1,149 @@
1
+ module ML10n
2
+ LANGUAGE_CODE_KEY = 'mloc_language_code'.freeze
3
+ COUNTRY_CODE_KEY = 'mloc_country_code'.freeze
4
+
5
+ class << self
6
+
7
+ # TODO add a mutex for when we load the localizations, in case people want to load the localizations
8
+ # at runtime
9
+
10
+ # all localizations are saved in this class variable
11
+ # localizations are namespaced using the language or locale they belong to
12
+ #
13
+ # for instance:
14
+ # ML10n.localizations['en'][:right] => 'right'
15
+ # ML10n.localizations['en'][:left] => 'left'
16
+ # ML10n.localizations['en']['US'][:greeting] => 'Howdie'
17
+ # ML10n.localizations['en']['AU'][:greeting] => "Good'ay"
18
+ #
19
+ # locales, including languages and countries use string keys while localization keys themselves are symbols
20
+ def localizations
21
+ @@localizations ||= {}
22
+ end
23
+
24
+ # files containing localizations
25
+ def localization_files
26
+ @@localization_files ||= ML10n.find_localization_files
27
+ end
28
+
29
+ # locations to look for localization files
30
+ def localization_dirs
31
+ @@localization_dirs ||= Merb::Plugins.config[:merb_babel][:localization_dirs].dup
32
+ end
33
+
34
+ # add a dir to look for localizations
35
+ def add_localization_dir(dir_path)
36
+ return ML10n.localization_dirs if dir_path.empty?
37
+ unless ML10n.localization_dirs.include?(dir_path)
38
+ ML10n.localization_dirs << dir_path
39
+ ML10n.reload_localization_files!
40
+ end
41
+ return ML10n.localization_dirs
42
+ end
43
+
44
+ def load_localization!
45
+
46
+ # look for localization files directly just in case new files were added
47
+ ML10n.reset_localization_files!
48
+ ML10n.find_localization_files.each do |l_file|
49
+ begin
50
+ l_hash = YAML.load_file(l_file)#.symbolize_keys
51
+ rescue Exception => e
52
+ # might raise a real error here in the future
53
+ p e.inspect
54
+ else
55
+ load_localization_hash(l_hash)
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ # go through the localization dirs and find the localization files
62
+ def find_localization_files
63
+ l_files = []
64
+ ML10n.localization_dirs.map do |l_dir|
65
+ Dir["#{l_dir}/*"].each do |file|
66
+ l_files << file unless l_files.include?(file)
67
+ end
68
+ end
69
+ return l_files
70
+ end
71
+
72
+ # reset the localization dirs and files to the plugin config
73
+ # careful when using this method since it will remove any localization files
74
+ # you loaded after the plugin started
75
+ #
76
+ # note that it won't clear the localization already loaded in memory
77
+ def reset_localization_files_and_dirs!
78
+ ML10n.reset_localization_dirs!
79
+ ML10n.reset_localization_files!
80
+ end
81
+
82
+ def reset_localization_dirs!
83
+ @@localization_dirs = nil
84
+ end
85
+
86
+ def reset_localization_files!
87
+ @@localization_files = nil
88
+ ML10n.find_localization_files
89
+ end
90
+
91
+ def reset_localizations!
92
+ @@localizations = {}
93
+ end
94
+
95
+ def reload_localization_files!
96
+ ML10n.reset_localization_files!
97
+ ML10n.find_localization_files
98
+ end
99
+
100
+ # localization helper
101
+ def localize(key, *options)
102
+ MI18n.localize(options.merge({:locale => locale}))
103
+ end
104
+
105
+ def localize_time(object, format, options)
106
+ table_for = proc do |table_name, key, default|
107
+ keys = ["DateFormat", table_name]
108
+ table = MI18n.lookup(options.merge(:keys => keys)) || {}
109
+ table[key] || default
110
+ end
111
+ format = format.to_s.dup
112
+ format.gsub!(/%a/) do
113
+ table_for["AbbrDayNames", object.wday, "%a"]
114
+ end
115
+ format.gsub!(/%A/) do
116
+ table_for["AbbrMonthNames", object.mon - 1, "%A"]
117
+ end
118
+ format.gsub!(/%B/) do
119
+ table_for["MonthNames", object.mon - 1, "%B"]
120
+ end
121
+ format.gsub!(/%p/) do
122
+ table_for["AmPm", object.hour < 12 ? 0 : 1, "%p"]
123
+ end if object.respond_to?(:hour)
124
+ format.gsub!(/%\{([a-zA-Z]\w*)\}/) do
125
+ object.send($1) rescue $1
126
+ end
127
+ object.strftime(format)
128
+ end
129
+
130
+ protected
131
+
132
+ def load_localization_hash(l_hash)
133
+ if l_hash.has_key?(LANGUAGE_CODE_KEY)
134
+ language = l_hash[LANGUAGE_CODE_KEY]
135
+ if l_hash.has_key?(COUNTRY_CODE_KEY)
136
+ country = l_hash[COUNTRY_CODE_KEY]
137
+ # load localization under the full locale namespace
138
+ ML10n.localizations[language] ||= {}
139
+ (ML10n.localizations[language][country] ||= {}).merge!(l_hash)
140
+ else
141
+ # load generic language localization
142
+ (ML10n.localizations[language] ||= {}).merge!(l_hash)
143
+ end
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,103 @@
1
+
2
+ # The MLocale module helps you set up a locale, language, country
3
+ # You don't have to use a locale, in some cases you might just want to use the language
4
+ module MLocale
5
+ def locale_from_request
6
+ if hal = request.env["HTTP_ACCEPT_LANGUAGE"]
7
+ hal.gsub!(/\s/, "")
8
+ result = hal.split(/,/).map do |v|
9
+ v.split(";q=")
10
+ end.map do |j|
11
+ [j[0], j[1] ? j[1].to_f : 1.0]
12
+ end.sort do |a,b|
13
+ -(a[1] <=> b[1])
14
+ end.map do |v|
15
+ Locale::Tag.parse(v[0])
16
+ end.first
17
+ return nil if result.nil?
18
+ language = result.language
19
+ country = result.country ||
20
+ LocaleDetector.country_from_language(language)
21
+ request.env[:locale] = "#{language}-#{country}"
22
+ end
23
+ end
24
+
25
+ # A locale is made of a language + country code, such as en-UK or en-US
26
+ def locale
27
+ request.env[:locale] || params[:locale] || (session ? session[:locale] : nil) || locale_from_request || default_locale
28
+ end
29
+
30
+ # Many people don't care about locales, they might just want to use languages instead
31
+ def language
32
+ request.env[:language] || params[:language] || language_from_locale || (session ? session[:language] : nil) || default_language
33
+ end
34
+
35
+ # The country is used when localizing currency or time
36
+ def country
37
+ request.env[:country] || params[:country] || country_from_locale || (session ? session[:country] : nil) || LocaleDetector.country_from_language(language) || default_country
38
+ end
39
+
40
+ # Extract the language from the locale
41
+ def language_from_locale
42
+ if request.env[:locale] && request.env[:locale] =~ locale_regexp
43
+ language, country = request.env[:locale].match(locale_regexp).captures
44
+ return language
45
+ else
46
+ return nil
47
+ end
48
+ end
49
+
50
+ # Extract the country from the locale
51
+ def country_from_locale
52
+ request.env[:locale] ? request.env[:locale][3..5].upcase : nil
53
+ end
54
+
55
+ # Defaults set in the plugin settings
56
+ # You can change the default settings by overwriting
57
+ # the Merb::Plugins.config[:merb_abel] hash in your settings
58
+ #
59
+ def default_locale
60
+ Merb::Plugins.config[:merb_babel] ? Merb::Plugins.config[:merb_babel][:default_locale] : nil
61
+ end
62
+
63
+ def default_language
64
+ Merb::Plugins.config[:merb_babel] ? Merb::Plugins.config[:merb_babel][:default_language] : nil
65
+ end
66
+
67
+ def default_country
68
+ Merb::Plugins.config[:merb_babel] ? Merb::Plugins.config[:merb_babel][:default_country] : nil
69
+ end
70
+ #
71
+ #### end of defaults
72
+
73
+ protected
74
+
75
+ def locale_regexp
76
+ /(.+)\-([a-z]{2})/i
77
+ end
78
+
79
+ # You can extend this method in application.rb
80
+ # example:
81
+ #
82
+ # def set_locale
83
+ # super
84
+ # session[:language] = language
85
+ # end
86
+ #
87
+ #
88
+ # takes a locale as in fr-FR or en-US
89
+ def set_locale
90
+ if locale =~ locale_regexp
91
+ language, country = locale.match(locale_regexp).captures
92
+ # Set the locale, language and country
93
+ language = language.downcase
94
+ country = country.upcase
95
+ request.env[:locale] = "#{language}-#{country}"
96
+ end
97
+
98
+ end
99
+
100
+ def set_language
101
+ request.env[:language] = language.downcase
102
+ end
103
+ end
@@ -0,0 +1,6 @@
1
+ # namespace :merb_babel do
2
+ # desc "Do something for merb_babel"
3
+ # task :default do
4
+ # puts "merb_babel doesn't do anything"
5
+ # end
6
+ # end
@@ -0,0 +1,13 @@
1
+ #################################################
2
+ # en-UK only localization
3
+ #
4
+ # only add localization specific to this locale
5
+ # other comman localizations must go in en.yml
6
+ #################################################
7
+ # required
8
+ mloc_language_code: en
9
+ # required for a locale localization file
10
+ mloc_country_code: UK
11
+ #################################################
12
+
13
+ greetings: Heya
@@ -0,0 +1,13 @@
1
+ #################################################
2
+ # en-US only localization
3
+ #
4
+ # only add localization specific to this locale
5
+ # other comman localizations must go in en.yml
6
+ #################################################
7
+ # required
8
+ mloc_language_code: en
9
+ # required for a locale localization file
10
+ mloc_country_code: US
11
+ #################################################
12
+
13
+ greetings: Howdie
@@ -0,0 +1,22 @@
1
+ #################################################
2
+ # English localization
3
+ #
4
+ # localization specific must go in their own file
5
+ # see en-US.yml for instance
6
+ #################################################
7
+ mloc_language_code: en
8
+ # Optional, the following key has the name of the localized language in its ow language.
9
+ mloc_language_name: English
10
+ # mloc_country:
11
+ #################################################
12
+
13
+
14
+ right: right
15
+ left: left
16
+ greetings: Hello
17
+
18
+ night:
19
+ greetings: Good evening
20
+
21
+ DateFormat:
22
+ AbbrDayNames: ["S", "M", "T", "W", "T", "F", "S"]
@@ -0,0 +1,23 @@
1
+ #################################################
2
+ # Japanese localization
3
+ #
4
+ # localization specific must go in their own file
5
+ # see ja-JP.yml for instance
6
+ #################################################
7
+ mloc_language_code: ja
8
+ # Optional, the following key has the name of the localized language in its ow language.
9
+ mloc_language_name: Japanese
10
+ # mloc_country:
11
+ #################################################
12
+
13
+
14
+ right: 右
15
+ left: 左
16
+ greetings: こんにちわ
17
+
18
+ night:
19
+ greetings: こんばんわ
20
+
21
+ DateFormat:
22
+ AbbrDayNames: ["日", "月", "火", "水", "木", "金", "土"]
23
+ AmPm: ["午前", "午後"]
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'country detector' do
4
+ it "should detect country from request" do
5
+ c = dispatch_to(TestController, :index, {},
6
+ 'HTTP_ACCEPT_LANGUAGE' => 'en-UK')
7
+ c.country.should == 'UK'
8
+ end
9
+
10
+ it "should detect language from request" do
11
+ c = dispatch_to(TestController, :index, {},
12
+ 'HTTP_ACCEPT_LANGUAGE' => 'fr-FR')
13
+ c.language.should == 'fr'
14
+ end
15
+
16
+ it "should detect full locale from request" do
17
+ c = dispatch_to(TestController, :index, {},
18
+ 'HTTP_ACCEPT_LANGUAGE' => 'en-UK')
19
+ c.locale.should == 'en-UK'
20
+ end
21
+
22
+ it "should detect full locale from request 2" do
23
+ c = dispatch_to(TestController, :index, {},
24
+ 'HTTP_ACCEPT_LANGUAGE' => 'en_UK')
25
+ c.language.should == 'en'
26
+ c.country.should == 'UK'
27
+ c.locale.should == 'en-UK'
28
+ end
29
+
30
+ it "should guess country from language" do
31
+ c = dispatch_to(TestController, :index, {},
32
+ 'HTTP_ACCEPT_LANGUAGE' => 'ja')
33
+ c.country.should == 'JP'
34
+ c.locale.should == 'ja-JP'
35
+ end
36
+
37
+ it "should detect language from request including candidates" do
38
+ c = dispatch_to(TestController, :index, {},
39
+ 'HTTP_ACCEPT_LANGUAGE' => 'ja,en;q=0.9,fr;q=0.8,de;q=0.7,es;q=0.6')
40
+ c.locale.should == 'ja-JP'
41
+ end
42
+ end
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe '#babelize' do
4
+
5
+ before(:each) do
6
+ Merb::Controller.send :include, Merb::GlobalHelpers
7
+ @c = dispatch_to(TestController, :index)
8
+ ML10n.add_localization_dir(File.expand_path(File.dirname(__FILE__) + "/lang"))
9
+ ML10n.add_localization_dir(File.expand_path(File.dirname(__FILE__) + "/other_lang_dir"))
10
+ ML10n.load_localization!
11
+ end
12
+
13
+ after(:each) do
14
+ ML10n.reset_localizations!
15
+ end
16
+
17
+ it "should babelize a word in English " do
18
+ @c.locale.should == 'en-US'
19
+ @c.language.should == 'en'
20
+ @c.country.should == 'US'
21
+ @c.babelize(:left).should == 'left'
22
+ end
23
+
24
+ it "should translate a word in English" do
25
+ @c.t(:left).should == 'left'
26
+ @c.translate(:left).should == 'left'
27
+ @c._(:left).should == 'left'
28
+ end
29
+
30
+ it "should translate a word in american English" do
31
+ @c.t(:greetings).should == 'Howdie'
32
+ end
33
+
34
+ it "should translate a word in british English" do
35
+ @c.request.env[:locale] = 'en-UK'
36
+ @c.t(:greetings).should == 'Heya'
37
+ end
38
+
39
+ it "should translate a word in French" do
40
+ @c.request.env[:language] = 'fr'
41
+ @c.t(:greetings).should == 'Salut'
42
+ end
43
+
44
+ it "should translate passing the full locale" do
45
+ @c.t(:greetings, :language => 'en', :country => 'UK').should == 'Heya'
46
+ @c.t(:greetings, :language => 'en', :country => 'US').should == 'Howdie'
47
+ end
48
+
49
+ it "should translate passing the language" do
50
+ @c.t(:greetings, :language => 'fr').should == 'Salut'
51
+ end
52
+
53
+ it "should translate with domain" do
54
+ @c.t(:night, :greetings, :language => 'en').should == 'Good evening'
55
+ @c.t(:night, :greetings, :language => 'ja').should == 'こんばんわ'
56
+ end
57
+
58
+ it "should localize date" do
59
+ date = Date.new(2009,1,1)
60
+ @c.t("%Y/%m/%d", date, :language => 'en').should == "2009/01/01"
61
+ @c.t("%Y/%{mon}/%{day}", date, :language => 'en').should == "2009/1/1"
62
+ @c.t("%a/%d", date, :language => 'en').should == "T/01"
63
+ @c.t("%a/%d", date, :language => 'en', :country => 'UK').should == "T/01"
64
+ @c.t("%a/%d", date, :language => 'ja').should == "木/01"
65
+ end
66
+
67
+ it "should localize time" do
68
+ time = Time.now
69
+ if time.hour < 12
70
+ @c.t("%p", time, :language => "ja").should == "午前"
71
+ else
72
+ @c.t("%p", time, :language => "ja").should == "午後"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "ML10n" do
4
+
5
+ before(:each) do
6
+ @lang_test_path = File.expand_path(File.dirname(__FILE__) + "/lang")
7
+ @lang_test_path_2 = File.expand_path(File.dirname(__FILE__) + "/other_lang_dir")
8
+ ML10n.reset_localization_files_and_dirs!
9
+ end
10
+
11
+ after(:each) do
12
+ ML10n.reset_localizations!
13
+ end
14
+
15
+ it "should have a list of localization directories" do
16
+ ML10n.localization_dirs.should == Merb::Plugins.config[:merb_babel][:localization_dirs]
17
+ end
18
+
19
+ it "should be able to add a new localization directory" do
20
+ ML10n.add_localization_dir(@lang_test_path)
21
+ ML10n.localization_dirs.include?(@lang_test_path)
22
+ end
23
+
24
+ it "should have a list of localization source files" do
25
+ ML10n.localization_files.should == []
26
+ ML10n.add_localization_dir(@lang_test_path)
27
+ ML10n.localization_files.include?("#{@lang_test_path}/en.yml").should be_true
28
+ ML10n.localization_files.include?("#{@lang_test_path}/en-US.yml").should be_true
29
+ end
30
+
31
+ it "should load localization files and have them available" do
32
+ ML10n.add_localization_dir(@lang_test_path)
33
+ ML10n.load_localization!
34
+ ML10n.localizations['en']['right'].should == 'right'
35
+ ML10n.localizations['en']['left'].should == 'left'
36
+ ML10n.localizations['en']['US']['greetings'].should == 'Howdie'
37
+ end
38
+
39
+ it "should load more localization files and have them available" do
40
+ ML10n.add_localization_dir(@lang_test_path)
41
+ ML10n.load_localization!
42
+ ML10n.localizations['en']['right'].should == 'right'
43
+ ML10n.localizations.has_key?('fr').should be_false
44
+
45
+ ML10n.add_localization_dir(@lang_test_path_2)
46
+ ML10n.load_localization!
47
+ ML10n.localizations['en']['right'].should == 'right'
48
+ ML10n.localizations.has_key?('fr').should be_true
49
+ ML10n.localizations['fr']['right'].should == 'la droite'
50
+ ML10n.localizations['fr']['left'].should == 'la gauche'
51
+ ML10n.localizations['fr']['greetings'].should == 'Salut'
52
+ end
53
+
54
+ end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+ describe 'using set_locale before filter, ' do
5
+ describe 'a controller' do
6
+
7
+ describe 'locale' do
8
+
9
+ it "should be set by default" do
10
+ c = dispatch_to(TestController, :index)
11
+ c.locale.should == 'en-US'
12
+ end
13
+
14
+ it "should be able to be set by passing a param" do
15
+ c = dispatch_to(TestController, :index, :locale => 'fr-FR')
16
+ c.locale.should == 'fr-FR'
17
+ end
18
+
19
+ it "should be able to be set using the session" do
20
+ c = dispatch_to(TestController, :index) do |controller|
21
+ controller.stub!(:session).and_return( :locale => "es-BO" )
22
+ end
23
+ c.locale.should == 'es-BO'
24
+ end
25
+
26
+ it "should be set using an url (when the routes are set properly)" do
27
+ #c = get('tests')
28
+ #c.locale.should == 'en-US'
29
+ c = get('en-US/tests')
30
+ c.locale.should == 'en-US'
31
+ c = get('en-UK/tests')
32
+ c.locale.should == 'en-UK'
33
+ end
34
+
35
+ it "should support longer locales (like zh-Hans-CN)" do
36
+ c = dispatch_to(TestController, :index, :locale => 'zh-Hans-CN')
37
+ c.locale.should == 'zh-hans-CN'
38
+ end
39
+
40
+ end
41
+
42
+ describe 'language' do
43
+
44
+ it "should be set by default" do
45
+ c = dispatch_to(TestController, :index)
46
+ c.language.should == 'en'
47
+ end
48
+
49
+ it "should be able to be set by passing a param" do
50
+ c = dispatch_to(TestController, :index, :language => 'fr')
51
+ c.language.should == 'fr'
52
+ end
53
+
54
+ it "should bet set when a locale was set by params" do
55
+ c = dispatch_to(TestController, :index, :locale => 'fr-FR')
56
+ c.locale.should == 'fr-FR'
57
+ c.language.should == 'fr'
58
+ end
59
+
60
+ it "should be set when a locale was set by params even with a long locale" do
61
+ c = dispatch_to(TestController, :index, :locale => 'zh-Hans-CN')
62
+ c.language.should == 'zh-hans'
63
+ end
64
+
65
+ it "should bet set when a locale was set by session" do
66
+ c = dispatch_to(TestController, :index) do |controller|
67
+ controller.stub!(:session).and_return( :locale => "es-BO" )
68
+ end
69
+ c.language.should == 'es'
70
+ end
71
+
72
+ it "should be set by the router" do
73
+ c = get('fr/languages')
74
+ c.language.should == 'fr'
75
+ c.locale.should == 'en-US'
76
+ # c = get('languages')
77
+ # c.language.should == 'en'
78
+ end
79
+
80
+ end
81
+
82
+ describe 'country' do
83
+
84
+ it "should be set by default" do
85
+ c = dispatch_to(TestController, :index)
86
+ c.country.should == 'US'
87
+ end
88
+
89
+ it "should be able to be set by passing a param" do
90
+ c = dispatch_to(TestController, :index, :country => 'ES')
91
+ c.country.should == 'ES'
92
+ end
93
+
94
+ it "should bet set when a locale was set by params" do
95
+ c = dispatch_to(TestController, :index, :locale => 'fr-FR')
96
+ c.country.should == 'FR'
97
+ end
98
+
99
+ it "should bet set when a locale was set by session" do
100
+ c = dispatch_to(TestController, :index) do |controller|
101
+ controller.stub!(:session).and_return( :locale => "es-BO" )
102
+ end
103
+ c.country.should == 'BO'
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ describe 'using set_language, ' do
112
+ describe 'a controller' do
113
+ describe 'language' do
114
+
115
+ it "should be set by default" do
116
+ c = dispatch_to(LanguageController, :index)
117
+ c.language.should == 'en'
118
+ end
119
+
120
+ it "should be able to be set by passing a param" do
121
+ c = dispatch_to(LanguageController, :index, :language => 'fr')
122
+ c.language.should == 'fr'
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,14 @@
1
+ #################################################
2
+ # French localization
3
+ #
4
+ # localization specific must go in their own file
5
+ # see en-US.yml for instance
6
+ #################################################
7
+ mloc_language_code: fr
8
+ # mloc_country:
9
+ #################################################
10
+
11
+ right: la droite
12
+ left: la gauche
13
+ greetings: Salut
14
+
@@ -0,0 +1,50 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require "rubygems"
4
+ require "spec"
5
+ require "merb-core"
6
+ require File.join(File.dirname(__FILE__), "..", 'lib', 'merb_babel')
7
+
8
+ default_options = {
9
+ :environment => 'test',
10
+ :adapter => 'runner',
11
+ :session_store => 'cookie',
12
+ :session_secret_key => '187a66e27674660418cf4499471d5a0587f360d0'
13
+ }
14
+
15
+ options = default_options.merge($START_OPTIONS || {})
16
+
17
+ Merb.disable(:initfile)
18
+ Merb.start_environment(options)
19
+
20
+ Spec::Runner.configure do |config|
21
+ config.include Merb::Test::ViewHelper
22
+ config.include Merb::Test::RouteHelper
23
+ config.include Merb::Test::RequestHelper
24
+ config.include Merb::Test::ControllerHelper
25
+ end
26
+
27
+ Merb.load_dependencies(:environment => 'test')
28
+
29
+ Merb::Router.prepare do |r|
30
+ r.match(/\/?(en\-US|en\-UK|es\-ES|es\-AR)?/).to(:locale => "[1]") do |l|
31
+ l.match("/tests").to(:controller => "test_controller")
32
+ end
33
+ r.match(/\/?(en|es|fr|de)?/).to(:language => "[1]") do |l|
34
+ l.match("/languages").to(:controller => "language_controller")
35
+ end
36
+ end
37
+
38
+
39
+
40
+ class TestController < Merb::Controller
41
+
42
+ before :set_locale
43
+ def index; end
44
+ end
45
+
46
+ class LanguageController < Merb::Controller
47
+
48
+ before :set_language
49
+ def index; end
50
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: merb_babel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Matt Aimonetti
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: locale
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.0
34
+ version:
35
+ description: Merb plugin that provides simple localization/internationalisation
36
+ email: mattaimonetti@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.markdown
43
+ - LICENSE
44
+ - TODO
45
+ files:
46
+ - LICENSE
47
+ - README.markdown
48
+ - Rakefile
49
+ - TODO
50
+ - lib/merb_babel
51
+ - lib/merb_babel/locale_detector.rb
52
+ - lib/merb_babel/m_i18n.rb
53
+ - lib/merb_babel/m_l10n.rb
54
+ - lib/merb_babel/m_locale.rb
55
+ - lib/merb_babel/merbtasks.rb
56
+ - lib/merb_babel.rb
57
+ - spec/lang
58
+ - spec/lang/en-UK.yml
59
+ - spec/lang/en-US.yml
60
+ - spec/lang/en.yml
61
+ - spec/lang/ja.yml
62
+ - spec/locale_detector_spec.rb
63
+ - spec/m_i18n_spec.rb
64
+ - spec/m_l10n_spec.rb
65
+ - spec/merb_babel_spec.rb
66
+ - spec/other_lang_dir
67
+ - spec/other_lang_dir/fr.yml
68
+ - spec/spec_helper.rb
69
+ has_rdoc: true
70
+ homepage: http://github.com/mattetti/merb_babel/
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
88
+ requirements: []
89
+
90
+ rubyforge_project: merb
91
+ rubygems_version: 1.3.1
92
+ signing_key:
93
+ specification_version: 2
94
+ summary: Merb plugin that provides simple localization/internationalisation
95
+ test_files: []
96
+