merb_babel 0.1.2

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/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
+