FEATURE: Allow plugins to register a new locale

This commit is contained in:
Gerhard Schlager
2018-01-25 12:09:18 +01:00
parent ba6cd83e3a
commit eb52c5469e
29 changed files with 480 additions and 71 deletions

View File

@@ -85,6 +85,7 @@ module JsLocaleHelper
end
def self.load_translations_merged(*locales)
locales = locales.compact
@loaded_merges ||= {}
@loaded_merges[locales.join('-')] ||= begin
all_translations = {}
@@ -101,9 +102,10 @@ module JsLocaleHelper
end
def self.translations_for(locale_str)
current_locale = I18n.locale
locale_sym = locale_str.to_sym
site_locale = SiteSetting.default_locale.to_sym
current_locale = I18n.locale
locale_sym = locale_str.to_sym
site_locale = SiteSetting.default_locale.to_sym
fallback_locale = LocaleSiteSetting.fallback_locale(locale_str)
I18n.locale = locale_sym
@@ -113,9 +115,9 @@ module JsLocaleHelper
elsif locale_sym == :en
load_translations(locale_sym)
elsif locale_sym == site_locale || site_locale == :en
load_translations_merged(locale_sym, :en)
load_translations_merged(locale_sym, fallback_locale, :en)
else
load_translations_merged(locale_sym, site_locale, :en)
load_translations_merged(locale_sym, fallback_locale, site_locale, :en)
end
I18n.locale = current_locale
@@ -125,11 +127,13 @@ module JsLocaleHelper
def self.output_locale(locale)
locale_str = locale.to_s
fallback_locale_str = LocaleSiteSetting.fallback_locale(locale_str)&.to_s
translations = Marshal.load(Marshal.dump(translations_for(locale_str)))
message_formats = strip_out_message_formats!(translations[locale_str]['js'])
message_formats.merge!(strip_out_message_formats!(translations[locale_str]['admin_js']))
result = generate_message_format(message_formats, locale_str)
mf_locale, mf_filename = find_message_format_locale([locale_str], true)
result = generate_message_format(message_formats, mf_locale, mf_filename)
translations.keys.each do |l|
translations[l].keys.each do |k|
@@ -140,7 +144,8 @@ module JsLocaleHelper
# I18n
result << "I18n.translations = #{translations.to_json};\n"
result << "I18n.locale = '#{locale_str}';\n"
result << "I18n.pluralizationRules.#{locale_str} = MessageFormat.locale.#{locale_str};\n" if locale_str != "en"
result << "I18n.fallbackLocale = '#{fallback_locale_str}';\n" if fallback_locale_str && fallback_locale_str != "en"
result << "I18n.pluralizationRules.#{locale_str} = MessageFormat.locale.#{mf_locale};\n" if mf_locale != "en"
# moment
result << File.read("#{Rails.root}/lib/javascripts/moment.js")
@@ -150,6 +155,41 @@ module JsLocaleHelper
result
end
def self.find_moment_locale(locale_chain)
path = "#{Rails.root}/lib/javascripts/moment_locale"
# moment.js uses a different naming scheme for locale files
locale_chain = locale_chain.map { |l| l.tr('_', '-').downcase }
find_locale(locale_chain, path, :moment_js, false)
end
def self.find_message_format_locale(locale_chain, fallback_to_english)
path = "#{Rails.root}/lib/javascripts/locale"
find_locale(locale_chain, path, :message_format, fallback_to_english)
end
def self.find_locale(locale_chain, path, type, fallback_to_english)
locale_chain.each do |locale|
plugin_locale = DiscoursePluginRegistry.locales[locale]
return plugin_locale[type] if plugin_locale&.has_key?(type)
filename = File.join(path, "#{locale}.js")
return [locale, filename] if File.exist?(filename)
end
# try again, but this time only with the language itself
locale_chain = locale_chain.map { |l| l.split(/[-_]/)[0] }
.uniq.reject { |l| locale_chain.include?(l) }
unless locale_chain.empty?
locale_data = find_locale(locale_chain, path, type, false)
return locale_data if locale_data
end
# English should alyways work
["en", File.join(path, "en.js")] if fallback_to_english
end
def self.moment_formats
result = ""
result << moment_format_function('short_date_no_year')
@@ -163,23 +203,13 @@ module JsLocaleHelper
"moment.fn.#{name.camelize(:lower)} = function(){ return this.format('#{format}'); };\n"
end
def self.moment_locale(locale_str)
# moment.js uses a different naming scheme for locale files
locale_str = locale_str.tr('_', '-').downcase
filename = "#{Rails.root}/lib/javascripts/moment_locale/#{locale_str}.js"
# try the language without the territory
locale_str = locale_str.split("-")[0]
filename = "#{Rails.root}/lib/javascripts/moment_locale/#{locale_str}.js" unless File.exists?(filename)
File.exists?(filename) ? File.read(filename) << "\n" : ""
def self.moment_locale(locale)
_, filename = find_moment_locale([locale])
filename && File.exist?(filename) ? File.read(filename) << "\n" : ""
end
def self.generate_message_format(message_formats, locale_str)
formats = message_formats.map { |k, v| k.inspect << " : " << compile_message_format(locale_str, v) }.join(", ")
filename = "#{Rails.root}/lib/javascripts/locale/#{locale_str}.js"
filename = "#{Rails.root}/lib/javascripts/locale/en.js" unless File.exists?(filename)
def self.generate_message_format(message_formats, locale, filename)
formats = message_formats.map { |k, v| k.inspect << " : " << compile_message_format(filename, locale, v) }.join(", ")
result = "MessageFormat = {locale: {}};\n"
result << "I18n._compiledMFs = {#{formats}};\n"
@@ -203,10 +233,9 @@ module JsLocaleHelper
end
end
def self.compile_message_format(locale, format)
def self.compile_message_format(path, locale, format)
with_context do |ctx|
path = "#{Rails.root}/lib/javascripts/locale/#{locale}.js"
ctx.load(path) if File.exists?(path)
ctx.load(path) if File.exist?(path)
ctx.eval("mf = new MessageFormat('#{locale}');")
ctx.eval("mf.precompile(mf.parse(#{format.inspect}))")
end