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:
Jean-Philippe Lang
2008-12-19 20:51:35 +00:00
parent 7ae224f5c2
commit 04fea923a4
1272 changed files with 119640 additions and 0 deletions
@@ -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'
+300
View File
@@ -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