Adds a branch for unlimited project hierarchy.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/work@2148 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
module GLoc
|
||||
|
||||
private
|
||||
|
||||
CONFIG= {} unless const_defined?(:CONFIG)
|
||||
unless CONFIG.frozen?
|
||||
CONFIG[:default_language] ||= :en
|
||||
CONFIG[:default_param_name] ||= 'lang'
|
||||
CONFIG[:default_cookie_name] ||= 'lang'
|
||||
CONFIG[:raise_string_not_found_errors]= true unless CONFIG.has_key?(:raise_string_not_found_errors)
|
||||
CONFIG[:verbose] ||= false
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
puts "GLoc v#{GLoc::VERSION} running in development mode. Strings can be modified at runtime."
|
||||
|
||||
module GLoc
|
||||
class << self
|
||||
|
||||
alias :actual_add_localized_strings :add_localized_strings
|
||||
def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil)
|
||||
_verbose_msg {"dev::add_localized_strings #{lang}, [#{symbol_hash.size}], #{override}, #{strings_charset ? strings_charset : 'nil'}"}
|
||||
STATE.push [:hash, lang, {}.merge(symbol_hash), override, strings_charset]
|
||||
_force_refresh
|
||||
end
|
||||
|
||||
alias :actual_load_localized_strings :load_localized_strings
|
||||
def load_localized_strings(dir=nil, override=true)
|
||||
_verbose_msg {"dev::load_localized_strings #{dir ? dir : 'nil'}, #{override}"}
|
||||
STATE.push [:dir, dir, override]
|
||||
_get_lang_file_list(dir).each {|filename| FILES[filename]= nil}
|
||||
end
|
||||
|
||||
alias :actual_clear_strings :clear_strings
|
||||
def clear_strings(*languages)
|
||||
_verbose_msg {"dev::clear_strings #{languages.map{|l|l.to_s}.join(', ')}"}
|
||||
STATE.push [:clear, languages.clone]
|
||||
_force_refresh
|
||||
end
|
||||
|
||||
alias :actual_clear_strings_except :clear_strings_except
|
||||
def clear_strings_except(*languages)
|
||||
_verbose_msg {"dev::clear_strings_except #{languages.map{|l|l.to_s}.join(', ')}"}
|
||||
STATE.push [:clear_except, languages.clone]
|
||||
_force_refresh
|
||||
end
|
||||
|
||||
# Replace methods
|
||||
[:_l, :_l_rule, :_l_has_string?, :similar_language, :valid_languages, :valid_language?].each do |m|
|
||||
class_eval <<-EOB
|
||||
alias :actual_#{m} :#{m}
|
||||
def #{m}(*args)
|
||||
_assert_gloc_strings_up_to_date
|
||||
actual_#{m}(*args)
|
||||
end
|
||||
EOB
|
||||
end
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
private
|
||||
|
||||
STATE= []
|
||||
FILES= {}
|
||||
|
||||
def _assert_gloc_strings_up_to_date
|
||||
changed= @@force_refresh
|
||||
|
||||
# Check if any lang files have changed
|
||||
unless changed
|
||||
FILES.each_pair {|f,mtime|
|
||||
changed ||= (File.stat(f).mtime != mtime)
|
||||
}
|
||||
end
|
||||
|
||||
return unless changed
|
||||
puts "GLoc reloading strings..."
|
||||
@@force_refresh= false
|
||||
|
||||
# Update file timestamps
|
||||
FILES.each_key {|f|
|
||||
FILES[f]= File.stat(f).mtime
|
||||
}
|
||||
|
||||
# Reload strings
|
||||
actual_clear_strings
|
||||
STATE.each {|s|
|
||||
case s[0]
|
||||
when :dir then actual_load_localized_strings s[1], s[2]
|
||||
when :hash then actual_add_localized_strings s[1], s[2], s[3], s[4]
|
||||
when :clear then actual_clear_strings(*s[1])
|
||||
when :clear_except then actual_clear_strings_except(*s[1])
|
||||
else raise "Invalid state id: '#{s[0]}'"
|
||||
end
|
||||
}
|
||||
_verbose_msg :stats
|
||||
end
|
||||
|
||||
@@force_refresh= false
|
||||
def _force_refresh
|
||||
@@force_refresh= true
|
||||
end
|
||||
|
||||
alias :super_get_internal_state_vars :_get_internal_state_vars
|
||||
def _get_internal_state_vars
|
||||
super_get_internal_state_vars + [ STATE, FILES ]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
module GLoc
|
||||
# These helper methods will be included in the InstanceMethods module.
|
||||
module Helpers
|
||||
def l_age(age) lwr :general_fmt_age, age end
|
||||
def l_date(date) l_strftime date, :general_fmt_date end
|
||||
def l_datetime(date) l_strftime date, :general_fmt_datetime end
|
||||
def l_datetime_short(date) l_strftime date, :general_fmt_datetime_short end
|
||||
def l_strftime(date,fmt) date.strftime l(fmt) end
|
||||
def l_time(time) l_strftime time, :general_fmt_time end
|
||||
def l_YesNo(value) l(value ? :general_text_Yes : :general_text_No) end
|
||||
def l_yesno(value) l(value ? :general_text_yes : :general_text_no) end
|
||||
|
||||
def l_lang_name(lang, display_lang=nil)
|
||||
ll display_lang || current_language, "general_lang_#{lang}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,134 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
require 'iconv'
|
||||
require 'gloc-version'
|
||||
|
||||
module GLoc
|
||||
class GLocError < StandardError #:nodoc:
|
||||
end
|
||||
class InvalidArgumentsError < GLocError #:nodoc:
|
||||
end
|
||||
class InvalidKeyError < GLocError #:nodoc:
|
||||
end
|
||||
class RuleNotFoundError < GLocError #:nodoc:
|
||||
end
|
||||
class StringNotFoundError < GLocError #:nodoc:
|
||||
end
|
||||
|
||||
class << self
|
||||
private
|
||||
|
||||
def _add_localized_data(lang, symbol_hash, override, target) #:nodoc:
|
||||
lang= lang.to_sym
|
||||
if override
|
||||
target[lang] ||= {}
|
||||
target[lang].merge!(symbol_hash)
|
||||
else
|
||||
symbol_hash.merge!(target[lang]) if target[lang]
|
||||
target[lang]= symbol_hash
|
||||
end
|
||||
end
|
||||
|
||||
def _add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) #:nodoc:
|
||||
_charset_required
|
||||
|
||||
# Convert all incoming strings to the gloc charset
|
||||
if strings_charset
|
||||
Iconv.open(get_charset(lang), strings_charset) do |i|
|
||||
symbol_hash.each_pair {|k,v| symbol_hash[k]= i.iconv(v)}
|
||||
end
|
||||
end
|
||||
|
||||
# Convert rules
|
||||
rules= {}
|
||||
old_kcode= $KCODE
|
||||
begin
|
||||
$KCODE= 'u'
|
||||
Iconv.open(UTF_8, get_charset(lang)) do |i|
|
||||
symbol_hash.each {|k,v|
|
||||
if /^_gloc_rule_(.+)$/ =~ k.to_s
|
||||
v= i.iconv(v) if v
|
||||
v= '""' if v.nil?
|
||||
rules[$1.to_sym]= eval "Proc.new do #{v} end"
|
||||
end
|
||||
}
|
||||
end
|
||||
ensure
|
||||
$KCODE= old_kcode
|
||||
end
|
||||
rules.keys.each {|k| symbol_hash.delete "_gloc_rule_#{k}".to_sym}
|
||||
|
||||
# Add new localized data
|
||||
LOWERCASE_LANGUAGES[lang.to_s.downcase]= lang
|
||||
_add_localized_data(lang, symbol_hash, override, LOCALIZED_STRINGS)
|
||||
_add_localized_data(lang, rules, override, RULES)
|
||||
end
|
||||
|
||||
def _charset_required #:nodoc:
|
||||
set_charset UTF_8 unless CONFIG[:internal_charset]
|
||||
end
|
||||
|
||||
def _get_internal_state_vars
|
||||
[ CONFIG, LOCALIZED_STRINGS, RULES, LOWERCASE_LANGUAGES ]
|
||||
end
|
||||
|
||||
def _get_lang_file_list(dir) #:nodoc:
|
||||
dir= File.join(RAILS_ROOT,'{.,vendor/plugins/*}','lang') if dir.nil?
|
||||
Dir[File.join(dir,'*.{yaml,yml}')]
|
||||
end
|
||||
|
||||
def _l(symbol, language, *arguments) #:nodoc:
|
||||
symbol= symbol.to_sym if symbol.is_a?(String)
|
||||
raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol)
|
||||
|
||||
translation= LOCALIZED_STRINGS[language][symbol] rescue nil
|
||||
if translation.nil?
|
||||
raise StringNotFoundError.new("There is no key called '#{symbol}' in the #{language} strings.") if CONFIG[:raise_string_not_found_errors]
|
||||
translation= symbol.to_s
|
||||
end
|
||||
|
||||
begin
|
||||
return translation % arguments
|
||||
rescue => e
|
||||
raise InvalidArgumentsError.new("Translation value #{translation.inspect} with arguments #{arguments.inspect} caused error '#{e.message}'")
|
||||
end
|
||||
end
|
||||
|
||||
def _l_has_string?(symbol,lang) #:nodoc:
|
||||
symbol= symbol.to_sym if symbol.is_a?(String)
|
||||
LOCALIZED_STRINGS[lang].has_key?(symbol.to_sym) rescue false
|
||||
end
|
||||
|
||||
def _l_rule(symbol,lang) #:nodoc:
|
||||
symbol= symbol.to_sym if symbol.is_a?(String)
|
||||
raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol)
|
||||
|
||||
r= RULES[lang][symbol] rescue nil
|
||||
raise RuleNotFoundError.new("There is no rule called '#{symbol}' in the #{lang} rules.") if r.nil?
|
||||
r
|
||||
end
|
||||
|
||||
def _verbose_msg(type=nil)
|
||||
return unless CONFIG[:verbose]
|
||||
x= case type
|
||||
when :stats
|
||||
x= valid_languages.map{|l| ":#{l}(#{LOCALIZED_STRINGS[l].size}/#{RULES[l].size})"}.sort.join(', ')
|
||||
"Current stats -- #{x}"
|
||||
else
|
||||
yield
|
||||
end
|
||||
puts "[GLoc] #{x}"
|
||||
end
|
||||
|
||||
public :_l, :_l_has_string?, :_l_rule
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
unless const_defined?(:LOCALIZED_STRINGS)
|
||||
LOCALIZED_STRINGS= {}
|
||||
RULES= {}
|
||||
LOWERCASE_LANGUAGES= {}
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,150 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
require 'date'
|
||||
|
||||
module ActionView #:nodoc:
|
||||
module Helpers #:nodoc:
|
||||
module DateHelper
|
||||
|
||||
unless const_defined?(:LOCALIZED_HELPERS)
|
||||
LOCALIZED_HELPERS= true
|
||||
LOCALIZED_MONTHNAMES = {}
|
||||
LOCALIZED_ABBR_MONTHNAMES = {}
|
||||
end
|
||||
|
||||
# This method uses <tt>current_language</tt> to return a localized string.
|
||||
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
||||
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
||||
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
||||
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
||||
distance_in_seconds = ((to_time - from_time).abs).round
|
||||
|
||||
case distance_in_minutes
|
||||
when 0..1
|
||||
return (distance_in_minutes==0) ? l(:actionview_datehelper_time_in_words_minute_less_than) : l(:actionview_datehelper_time_in_words_minute_single) unless include_seconds
|
||||
case distance_in_seconds
|
||||
when 0..5 then lwr(:actionview_datehelper_time_in_words_second_less_than, 5)
|
||||
when 6..10 then lwr(:actionview_datehelper_time_in_words_second_less_than, 10)
|
||||
when 11..20 then lwr(:actionview_datehelper_time_in_words_second_less_than, 20)
|
||||
when 21..40 then l(:actionview_datehelper_time_in_words_minute_half)
|
||||
when 41..59 then l(:actionview_datehelper_time_in_words_minute_less_than)
|
||||
else l(:actionview_datehelper_time_in_words_minute)
|
||||
end
|
||||
|
||||
when 2..45 then lwr(:actionview_datehelper_time_in_words_minute, distance_in_minutes)
|
||||
when 46..90 then l(:actionview_datehelper_time_in_words_hour_about_single)
|
||||
when 90..1440 then lwr(:actionview_datehelper_time_in_words_hour_about, (distance_in_minutes.to_f / 60.0).round)
|
||||
when 1441..2880 then lwr(:actionview_datehelper_time_in_words_day, 1)
|
||||
else lwr(:actionview_datehelper_time_in_words_day, (distance_in_minutes / 1440).round)
|
||||
end
|
||||
end
|
||||
|
||||
# This method has been modified so that a localized string can be appended to the day numbers.
|
||||
def select_day(date, options = {})
|
||||
day_options = []
|
||||
prefix = l :actionview_datehelper_select_day_prefix
|
||||
|
||||
1.upto(31) do |day|
|
||||
day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ?
|
||||
%(<option value="#{day}" selected="selected">#{day}#{prefix}</option>\n) :
|
||||
%(<option value="#{day}">#{day}#{prefix}</option>\n)
|
||||
)
|
||||
end
|
||||
|
||||
select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
||||
end
|
||||
|
||||
# This method has been modified so that
|
||||
# * the month names are localized.
|
||||
# * it uses options: <tt>:min_date</tt>, <tt>:max_date</tt>, <tt>:start_month</tt>, <tt>:end_month</tt>
|
||||
# * a localized string can be appended to the month numbers when the <tt>:use_month_numbers</tt> option is specified.
|
||||
def select_month(date, options = {})
|
||||
unless LOCALIZED_MONTHNAMES.has_key?(current_language)
|
||||
LOCALIZED_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names).split(',')
|
||||
LOCALIZED_ABBR_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names_abbr).split(',')
|
||||
end
|
||||
|
||||
month_options = []
|
||||
month_names = options[:use_short_month] ? LOCALIZED_ABBR_MONTHNAMES[current_language] : LOCALIZED_MONTHNAMES[current_language]
|
||||
|
||||
if options.has_key?(:min_date) && options.has_key?(:max_date)
|
||||
if options[:min_date].year == options[:max_date].year
|
||||
start_month, end_month = options[:min_date].month, options[:max_date].month
|
||||
end
|
||||
end
|
||||
start_month = (options[:start_month] || 1) unless start_month
|
||||
end_month = (options[:end_month] || 12) unless end_month
|
||||
prefix = l :actionview_datehelper_select_month_prefix
|
||||
|
||||
start_month.upto(end_month) do |month_number|
|
||||
month_name = if options[:use_month_numbers]
|
||||
"#{month_number}#{prefix}"
|
||||
elsif options[:add_month_numbers]
|
||||
month_number.to_s + ' - ' + month_names[month_number]
|
||||
else
|
||||
month_names[month_number]
|
||||
end
|
||||
|
||||
month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
|
||||
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
|
||||
%(<option value="#{month_number}">#{month_name}</option>\n)
|
||||
)
|
||||
end
|
||||
|
||||
select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
||||
end
|
||||
|
||||
# This method has been modified so that
|
||||
# * it uses options: <tt>:min_date</tt>, <tt>:max_date</tt>
|
||||
# * a localized string can be appended to the years numbers.
|
||||
def select_year(date, options = {})
|
||||
year_options = []
|
||||
y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
|
||||
|
||||
start_year = options.has_key?(:min_date) ? options[:min_date].year : (options[:start_year] || y-5)
|
||||
end_year = options.has_key?(:max_date) ? options[:max_date].year : (options[:end_year] || y+5)
|
||||
step_val = start_year < end_year ? 1 : -1
|
||||
prefix = l :actionview_datehelper_select_year_prefix
|
||||
|
||||
start_year.step(end_year, step_val) do |year|
|
||||
year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ?
|
||||
%(<option value="#{year}" selected="selected">#{year}#{prefix}</option>\n) :
|
||||
%(<option value="#{year}">#{year}#{prefix}</option>\n)
|
||||
)
|
||||
end
|
||||
|
||||
select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
||||
end
|
||||
|
||||
# added by JP Lang
|
||||
# select_html is a rails private method and changed in 1.2
|
||||
# implementation added here for compatibility
|
||||
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false, disabled = false)
|
||||
select_html = %(<select name="#{prefix || "date"})
|
||||
select_html << "[#{type}]" unless discard_type
|
||||
select_html << %(")
|
||||
select_html << %( disabled="disabled") if disabled
|
||||
select_html << %(>\n)
|
||||
select_html << %(<option value=""></option>\n) if include_blank
|
||||
select_html << options.to_s
|
||||
select_html << "</select>\n"
|
||||
end
|
||||
end
|
||||
|
||||
# The private method <tt>add_options</tt> is overridden so that "Please select" is localized.
|
||||
class InstanceTag
|
||||
private
|
||||
|
||||
def add_options(option_tags, options, value = nil)
|
||||
option_tags = "<option value=\"\"></option>\n" + option_tags if options[:include_blank]
|
||||
|
||||
if options[:prompt]
|
||||
("<option value=\"\">--- #{options[:prompt].kind_of?(String) ? options[:prompt] : l(:actionview_instancetag_blank_option)} ---</option>\n") + option_tags
|
||||
else
|
||||
option_tags
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,252 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
require 'gloc'
|
||||
|
||||
module ActionController #:nodoc:
|
||||
class Base #:nodoc:
|
||||
include GLoc
|
||||
end
|
||||
module Filters #:nodoc:
|
||||
module ClassMethods
|
||||
|
||||
# This filter attempts to auto-detect the clients desired language.
|
||||
# It first checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE
|
||||
# request header. If a language is found to match or be similar to a currently
|
||||
# valid language, then it sets the current_language of the controller.
|
||||
#
|
||||
# class ExampleController < ApplicationController
|
||||
# set_language :en
|
||||
# autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback
|
||||
# autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false
|
||||
# ...
|
||||
# def lang_not_autodetected_callback
|
||||
# redirect_to somewhere
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# The <tt>args</tt> for this filter are exactly the same the arguments of
|
||||
# <tt>before_filter</tt> with the following exceptions:
|
||||
# * <tt>:check_params</tt> -- If false, then params will not be checked for a language.
|
||||
# If a String, then this will value will be used as the name of the param.
|
||||
# * <tt>:check_cookie</tt> -- If false, then the cookie will not be checked for a language.
|
||||
# If a String, then this will value will be used as the name of the cookie.
|
||||
# * <tt>:check_accept_header</tt> -- If false, then HTTP_ACCEPT_LANGUAGE will not be checked for a language.
|
||||
# * <tt>:on_set_lang</tt> -- You can specify the name of a callback function to be called when the language
|
||||
# is successfully detected and set. The param must be a Symbol or a String which is the name of the function.
|
||||
# The callback function must accept one argument (the language) and must be instance level.
|
||||
# * <tt>:on_no_lang</tt> -- You can specify the name of a callback function to be called when the language
|
||||
# couldn't be detected automatically. The param must be a Symbol or a String which is the name of the function.
|
||||
# The callback function must be instance level.
|
||||
#
|
||||
# You override the default names of the param or cookie by calling <tt>GLoc.set_config :default_param_name => 'new_param_name'</tt>
|
||||
# and <tt>GLoc.set_config :default_cookie_name => 'new_cookie_name'</tt>.
|
||||
def autodetect_language_filter(*args)
|
||||
options= args.last.is_a?(Hash) ? args.last : {}
|
||||
x= 'Proc.new { |c| l= nil;'
|
||||
# :check_params
|
||||
unless (v= options.delete(:check_params)) == false
|
||||
name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)'
|
||||
x << "l ||= GLoc.similar_language(c.params[#{name}]);"
|
||||
end
|
||||
# :check_cookie
|
||||
unless (v= options.delete(:check_cookie)) == false
|
||||
name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)'
|
||||
x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);"
|
||||
end
|
||||
# :check_accept_header
|
||||
unless options.delete(:check_accept_header) == false
|
||||
x << %<
|
||||
unless l
|
||||
a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil
|
||||
a.each {|x| l ||= GLoc.similar_language(x)} if a
|
||||
end; >
|
||||
end
|
||||
# Set language
|
||||
x << 'ret= true;'
|
||||
x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; '
|
||||
if options.has_key?(:on_set_lang)
|
||||
x << "ret= c.#{options.delete(:on_set_lang)}(l);"
|
||||
end
|
||||
if options.has_key?(:on_no_lang)
|
||||
x << "else; ret= c.#{options.delete(:on_no_lang)};"
|
||||
end
|
||||
x << 'end; ret }'
|
||||
|
||||
# Create filter
|
||||
block= eval x
|
||||
before_filter(*args, &block)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
module ActionMailer #:nodoc:
|
||||
# In addition to including GLoc, <tt>render_message</tt> is also overridden so
|
||||
# that mail templates contain the current language at the end of the file.
|
||||
# Eg. <tt>deliver_hello</tt> will render <tt>hello_en.rhtml</tt>.
|
||||
class Base
|
||||
include GLoc
|
||||
private
|
||||
alias :render_message_without_gloc :render_message
|
||||
def render_message(method_name, body)
|
||||
template = File.exist?("#{template_path}/#{method_name}_#{current_language}.rhtml") ? "#{method_name}_#{current_language}" : "#{method_name}"
|
||||
render_message_without_gloc(template, body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
module ActionView #:nodoc:
|
||||
# <tt>initialize</tt> is overridden so that new instances of this class inherit
|
||||
# the current language of the controller.
|
||||
class Base
|
||||
include GLoc
|
||||
|
||||
alias :initialize_without_gloc :initialize
|
||||
def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
|
||||
initialize_without_gloc(base_path, assigns_for_first_render, controller)
|
||||
set_language controller.current_language unless controller.nil?
|
||||
end
|
||||
end
|
||||
|
||||
module Helpers #:nodoc:
|
||||
class InstanceTag
|
||||
include GLoc
|
||||
# Inherits the current language from the template object.
|
||||
def current_language
|
||||
@template_object.current_language
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
module ActiveRecord #:nodoc:
|
||||
class Base #:nodoc:
|
||||
include GLoc
|
||||
end
|
||||
|
||||
# class Errors
|
||||
# include GLoc
|
||||
# alias :add_without_gloc :add
|
||||
# # The GLoc version of this method provides two extra features
|
||||
# # * If <tt>msg</tt> is a string, it will be considered a GLoc string key.
|
||||
# # * If <tt>msg</tt> is an array, the first element will be considered
|
||||
# # the string and the remaining elements will be considered arguments for the
|
||||
# # string. Eg. <tt>['Hi %s.','John']</tt>
|
||||
# def add(attribute, msg= @@default_error_messages[:invalid])
|
||||
# if msg.is_a?(Array)
|
||||
# args= msg.clone
|
||||
# msg= args.shift
|
||||
# args= nil if args.empty?
|
||||
# end
|
||||
# msg= ltry(msg)
|
||||
# msg= msg % args unless args.nil?
|
||||
# add_without_gloc(attribute, msg)
|
||||
# end
|
||||
# # Inherits the current language from the base record.
|
||||
# def current_language
|
||||
# @base.current_language
|
||||
# end
|
||||
# end
|
||||
|
||||
class Errors
|
||||
include GLoc
|
||||
|
||||
def full_messages
|
||||
full_messages = []
|
||||
|
||||
@errors.each_key do |attr|
|
||||
@errors[attr].each do |msg|
|
||||
next if msg.nil?
|
||||
|
||||
if attr == "base"
|
||||
full_messages << (msg.is_a?(Symbol) ? l(msg) : msg)
|
||||
else
|
||||
full_messages << @base.class.human_attribute_name(attr) + " " + (msg.is_a?(Symbol) ? l(msg) : msg.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
full_messages
|
||||
end
|
||||
end
|
||||
|
||||
module Validations #:nodoc:
|
||||
module ClassMethods
|
||||
# The default Rails version of this function creates an error message and then
|
||||
# passes it to ActiveRecord.Errors.
|
||||
# The GLoc version of this method, sends an array to ActiveRecord.Errors that will
|
||||
# be turned into a string by ActiveRecord.Errors which in turn allows for the message
|
||||
# of this validation function to be a GLoc string key.
|
||||
def validates_length_of(*attrs)
|
||||
# Merge given options with defaults.
|
||||
options = {
|
||||
:too_long => ActiveRecord::Errors.default_error_messages[:too_long],
|
||||
:too_short => ActiveRecord::Errors.default_error_messages[:too_short],
|
||||
:wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
|
||||
}.merge(DEFAULT_VALIDATION_OPTIONS)
|
||||
options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
|
||||
|
||||
# Ensure that one and only one range option is specified.
|
||||
range_options = ALL_RANGE_OPTIONS & options.keys
|
||||
case range_options.size
|
||||
when 0
|
||||
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
|
||||
when 1
|
||||
# Valid number of options; do nothing.
|
||||
else
|
||||
raise ArgumentError, 'Too many range options specified. Choose only one.'
|
||||
end
|
||||
|
||||
# Get range option and value.
|
||||
option = range_options.first
|
||||
option_value = options[range_options.first]
|
||||
|
||||
case option
|
||||
when :within, :in
|
||||
raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
|
||||
|
||||
too_short = [options[:too_short] , option_value.begin]
|
||||
too_long = [options[:too_long] , option_value.end ]
|
||||
|
||||
validates_each(attrs, options) do |record, attr, value|
|
||||
if value.nil? or value.split(//).size < option_value.begin
|
||||
record.errors.add(attr, too_short)
|
||||
elsif value.split(//).size > option_value.end
|
||||
record.errors.add(attr, too_long)
|
||||
end
|
||||
end
|
||||
when :is, :minimum, :maximum
|
||||
raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
|
||||
|
||||
# Declare different validations per option.
|
||||
validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
|
||||
message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
|
||||
|
||||
message = [(options[:message] || options[message_options[option]]) , option_value]
|
||||
|
||||
validates_each(attrs, options) do |record, attr, value|
|
||||
if value.kind_of?(String)
|
||||
record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
|
||||
else
|
||||
record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :validates_size_of, :validates_length_of
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
module ApplicationHelper #:nodoc:
|
||||
include GLoc
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
module Test # :nodoc:
|
||||
module Unit # :nodoc:
|
||||
class TestCase # :nodoc:
|
||||
include GLoc
|
||||
end; end; end
|
||||
@@ -0,0 +1,12 @@
|
||||
module GLoc
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 1
|
||||
MINOR = 1
|
||||
TINY = nil
|
||||
|
||||
STRING= [MAJOR, MINOR, TINY].delete_if{|x|x.nil?}.join('.')
|
||||
def self.to_s; STRING end
|
||||
end
|
||||
end
|
||||
|
||||
puts "NOTICE: You are using a dev version of GLoc." if GLoc::VERSION::TINY == 'DEV'
|
||||
@@ -0,0 +1,300 @@
|
||||
# Copyright (c) 2005-2006 David Barri
|
||||
|
||||
require 'yaml'
|
||||
require 'gloc-internal'
|
||||
require 'gloc-helpers'
|
||||
|
||||
module GLoc
|
||||
UTF_8= 'utf-8'
|
||||
SHIFT_JIS= 'sjis'
|
||||
EUC_JP= 'euc-jp'
|
||||
|
||||
# This module will be included in both instances and classes of GLoc includees.
|
||||
# It is also included as class methods in the GLoc module itself.
|
||||
module InstanceMethods
|
||||
include Helpers
|
||||
|
||||
# Returns a localized string.
|
||||
def l(symbol, *arguments)
|
||||
return GLoc._l(symbol,current_language,*arguments)
|
||||
end
|
||||
|
||||
# Returns a localized string in a specified language.
|
||||
# This does not effect <tt>current_language</tt>.
|
||||
def ll(lang, symbol, *arguments)
|
||||
return GLoc._l(symbol,lang.to_sym,*arguments)
|
||||
end
|
||||
|
||||
# Returns a localized string if the argument is a Symbol, else just returns the argument.
|
||||
def ltry(possible_key)
|
||||
possible_key.is_a?(Symbol) ? l(possible_key) : possible_key
|
||||
end
|
||||
|
||||
# Uses the default GLoc rule to return a localized string.
|
||||
# See lwr_() for more info.
|
||||
def lwr(symbol, *arguments)
|
||||
lwr_(:default, symbol, *arguments)
|
||||
end
|
||||
|
||||
# Uses a <em>rule</em> to return a localized string.
|
||||
# A rule is a function that uses specified arguments to return a localization key prefix.
|
||||
# The prefix is appended to the localization key originally specified, to create a new key which
|
||||
# is then used to lookup a localized string.
|
||||
def lwr_(rule, symbol, *arguments)
|
||||
GLoc._l("#{symbol}#{GLoc::_l_rule(rule,current_language).call(*arguments)}",current_language,*arguments)
|
||||
end
|
||||
|
||||
# Returns <tt>true</tt> if a localized string with the specified key exists.
|
||||
def l_has_string?(symbol)
|
||||
return GLoc._l_has_string?(symbol,current_language)
|
||||
end
|
||||
|
||||
# Sets the current language for this instance/class.
|
||||
# Setting the language of a class effects all instances unless the instance has its own language defined.
|
||||
def set_language(language)
|
||||
GLoc.current_language = language
|
||||
end
|
||||
|
||||
# Sets the current language if the language passed is a valid language.
|
||||
# If the language was valid, this method returns <tt>true</tt> else it will return <tt>false</tt>.
|
||||
# Note that <tt>nil</tt> is not a valid language.
|
||||
# See set_language(language) for more info.
|
||||
def set_language_if_valid(language)
|
||||
if GLoc.valid_language?(language)
|
||||
set_language(language)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Instance
|
||||
|
||||
include ::GLoc::InstanceMethods
|
||||
# Returns the instance-level current language, or if not set, returns the class-level current language.
|
||||
def current_language
|
||||
GLoc.current_language
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Class
|
||||
|
||||
# All classes/modules that include GLoc will also gain these class methods.
|
||||
# Notice that the GLoc::InstanceMethods module is also included.
|
||||
module ClassMethods
|
||||
include ::GLoc::InstanceMethods
|
||||
# Returns the current language, or if not set, returns the GLoc current language.
|
||||
def current_language
|
||||
GLoc.current_language
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(target) #:nodoc:
|
||||
super
|
||||
class << target
|
||||
include ::GLoc::ClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# GLoc module
|
||||
|
||||
class << self
|
||||
include ::GLoc::InstanceMethods
|
||||
|
||||
@@current_language = nil
|
||||
|
||||
# Returns the current language
|
||||
def current_language
|
||||
@@current_language || GLoc::CONFIG[:default_language]
|
||||
end
|
||||
|
||||
def current_language=(lang)
|
||||
@@current_language = lang.blank? ? nil : lang.to_sym
|
||||
end
|
||||
|
||||
# Adds a collection of localized strings to the in-memory string store.
|
||||
def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil)
|
||||
_verbose_msg {"Adding #{symbol_hash.size} #{lang} strings."}
|
||||
_add_localized_strings(lang, symbol_hash, override, strings_charset)
|
||||
_verbose_msg :stats
|
||||
end
|
||||
|
||||
# Creates a backup of the internal state of GLoc (ie. strings, langs, rules, config)
|
||||
# and optionally clears everything.
|
||||
def backup_state(clear=false)
|
||||
s= _get_internal_state_vars.map{|o| o.clone}
|
||||
_get_internal_state_vars.each{|o| o.clear} if clear
|
||||
s
|
||||
end
|
||||
|
||||
# Removes all localized strings from memory, either of a certain language (or languages),
|
||||
# or entirely.
|
||||
def clear_strings(*languages)
|
||||
if languages.empty?
|
||||
_verbose_msg {"Clearing all strings"}
|
||||
LOCALIZED_STRINGS.clear
|
||||
LOWERCASE_LANGUAGES.clear
|
||||
else
|
||||
languages.each {|l|
|
||||
_verbose_msg {"Clearing :#{l} strings"}
|
||||
l= l.to_sym
|
||||
LOCALIZED_STRINGS.delete l
|
||||
LOWERCASE_LANGUAGES.each_pair {|k,v| LOWERCASE_LANGUAGES.delete k if v == l}
|
||||
}
|
||||
end
|
||||
end
|
||||
alias :_clear_strings :clear_strings
|
||||
|
||||
# Removes all localized strings from memory, except for those of certain specified languages.
|
||||
def clear_strings_except(*languages)
|
||||
clear= (LOCALIZED_STRINGS.keys - languages)
|
||||
_clear_strings(*clear) unless clear.empty?
|
||||
end
|
||||
|
||||
# Returns the charset used to store localized strings in memory.
|
||||
def get_charset(lang)
|
||||
CONFIG[:internal_charset_per_lang][lang] || CONFIG[:internal_charset]
|
||||
end
|
||||
|
||||
# Returns a GLoc configuration value.
|
||||
def get_config(key)
|
||||
CONFIG[key]
|
||||
end
|
||||
|
||||
# Loads the localized strings that are included in the GLoc library.
|
||||
def load_gloc_default_localized_strings(override=false)
|
||||
GLoc.load_localized_strings "#{File.dirname(__FILE__)}/../lang", override
|
||||
end
|
||||
|
||||
# Loads localized strings from all yml files in the specifed directory.
|
||||
def load_localized_strings(dir=nil, override=true)
|
||||
_charset_required
|
||||
_get_lang_file_list(dir).each {|filename|
|
||||
|
||||
# Load file
|
||||
raw_hash = YAML::load(File.read(filename))
|
||||
raw_hash={} unless raw_hash.kind_of?(Hash)
|
||||
filename =~ /([^\/\\]+)\.ya?ml$/
|
||||
lang = $1.to_sym
|
||||
file_charset = raw_hash['file_charset'] || UTF_8
|
||||
|
||||
# Convert string keys to symbols
|
||||
dest_charset= get_charset(lang)
|
||||
_verbose_msg {"Reading file #{filename} [charset: #{file_charset} --> #{dest_charset}]"}
|
||||
symbol_hash = {}
|
||||
Iconv.open(dest_charset, file_charset) do |i|
|
||||
raw_hash.each {|key, value|
|
||||
symbol_hash[key.to_sym] = i.iconv(value)
|
||||
}
|
||||
end
|
||||
|
||||
# Add strings to repos
|
||||
_add_localized_strings(lang, symbol_hash, override)
|
||||
}
|
||||
_verbose_msg :stats
|
||||
end
|
||||
|
||||
# Restores a backup of GLoc's internal state that was made with backup_state.
|
||||
def restore_state(state)
|
||||
_get_internal_state_vars.each do |o|
|
||||
o.clear
|
||||
o.send o.respond_to?(:merge!) ? :merge! : :concat, state.shift
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the charset used to internally store localized strings.
|
||||
# You can set the charset to use for a specific language or languages,
|
||||
# or if none are specified the charset for ALL localized strings will be set.
|
||||
def set_charset(new_charset, *langs)
|
||||
CONFIG[:internal_charset_per_lang] ||= {}
|
||||
|
||||
# Convert symbol shortcuts
|
||||
if new_charset.is_a?(Symbol)
|
||||
new_charset= case new_charset
|
||||
when :utf8, :utf_8 then UTF_8
|
||||
when :sjis, :shift_jis, :shiftjis then SHIFT_JIS
|
||||
when :eucjp, :euc_jp then EUC_JP
|
||||
else new_charset.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Convert existing strings
|
||||
(langs.empty? ? LOCALIZED_STRINGS.keys : langs).each do |lang|
|
||||
cur_charset= get_charset(lang)
|
||||
if cur_charset && new_charset != cur_charset
|
||||
_verbose_msg {"Converting :#{lang} strings from #{cur_charset} to #{new_charset}"}
|
||||
Iconv.open(new_charset, cur_charset) do |i|
|
||||
bundle= LOCALIZED_STRINGS[lang]
|
||||
bundle.each_pair {|k,v| bundle[k]= i.iconv(v)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set new charset value
|
||||
if langs.empty?
|
||||
_verbose_msg {"Setting GLoc charset for all languages to #{new_charset}"}
|
||||
CONFIG[:internal_charset]= new_charset
|
||||
CONFIG[:internal_charset_per_lang].clear
|
||||
else
|
||||
langs.each do |lang|
|
||||
_verbose_msg {"Setting GLoc charset for :#{lang} strings to #{new_charset}"}
|
||||
CONFIG[:internal_charset_per_lang][lang]= new_charset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sets GLoc configuration values.
|
||||
def set_config(hash)
|
||||
CONFIG.merge! hash
|
||||
end
|
||||
|
||||
# Sets the $KCODE global variable according to a specified charset, or else the
|
||||
# current default charset for the default language.
|
||||
def set_kcode(charset=nil)
|
||||
_charset_required
|
||||
charset ||= get_charset(current_language)
|
||||
$KCODE= case charset
|
||||
when UTF_8 then 'u'
|
||||
when SHIFT_JIS then 's'
|
||||
when EUC_JP then 'e'
|
||||
else 'n'
|
||||
end
|
||||
_verbose_msg {"$KCODE set to #{$KCODE}"}
|
||||
end
|
||||
|
||||
# Tries to find a valid language that is similar to the argument passed.
|
||||
# Eg. :en, :en_au, :EN_US are all similar languages.
|
||||
# Returns <tt>nil</tt> if no similar languages are found.
|
||||
def similar_language(lang)
|
||||
return nil if lang.nil?
|
||||
return lang.to_sym if valid_language?(lang)
|
||||
# Check lowercase without dashes
|
||||
lang= lang.to_s.downcase.gsub('-','_')
|
||||
return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
|
||||
# Check without dialect
|
||||
if lang.to_s =~ /^([a-z]+?)[^a-z].*/
|
||||
lang= $1
|
||||
return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
|
||||
end
|
||||
# Check other dialects
|
||||
lang= "#{lang}_"
|
||||
LOWERCASE_LANGUAGES.keys.each {|k| return LOWERCASE_LANGUAGES[k] if k.starts_with?(lang)}
|
||||
# Nothing found
|
||||
nil
|
||||
end
|
||||
|
||||
# Returns an array of (currently) valid languages (ie. languages for which localized data exists).
|
||||
def valid_languages
|
||||
LOCALIZED_STRINGS.keys
|
||||
end
|
||||
|
||||
# Returns <tt>true</tt> if there are any localized strings for a specified language.
|
||||
# Note that although <tt>set_langauge nil</tt> is perfectly valid, <tt>nil</tt> is not a valid language.
|
||||
def valid_language?(language)
|
||||
LOCALIZED_STRINGS.has_key? language.to_sym rescue false
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user