mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 03:16:41 +08:00
FEATURE: Allow plugins to register a new locale
This commit is contained in:
parent
ba6cd83e3a
commit
eb52c5469e
|
@ -1,7 +1,5 @@
|
||||||
app/assets/javascripts/env.js
|
app/assets/javascripts/env.js
|
||||||
app/assets/javascripts/main_include.js
|
|
||||||
app/assets/javascripts/main_include_admin.js
|
app/assets/javascripts/main_include_admin.js
|
||||||
app/assets/javascripts/pagedown_custom.js
|
|
||||||
app/assets/javascripts/vendor.js
|
app/assets/javascripts/vendor.js
|
||||||
app/assets/javascripts/locales/i18n.js
|
app/assets/javascripts/locales/i18n.js
|
||||||
app/assets/javascripts/ember-addons/
|
app/assets/javascripts/ember-addons/
|
||||||
|
@ -11,11 +9,9 @@ lib/javascripts/messageformat.js
|
||||||
lib/javascripts/moment.js
|
lib/javascripts/moment.js
|
||||||
lib/javascripts/moment_locale/
|
lib/javascripts/moment_locale/
|
||||||
lib/highlight_js/
|
lib/highlight_js/
|
||||||
|
plugins/**/lib/javascripts/locale
|
||||||
public/javascripts/
|
public/javascripts/
|
||||||
spec/phantom_js/smoke_test.js
|
|
||||||
vendor/
|
vendor/
|
||||||
test/javascripts/test_helper.js
|
test/javascripts/test_helper.js
|
||||||
test/javascripts/test_helper.js
|
|
||||||
test/javascripts/fixtures
|
test/javascripts/fixtures
|
||||||
test/javascripts/helpers/assertions.js
|
test/javascripts/helpers/assertions.js
|
||||||
app/assets/javascripts/ember-addons/
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ I18n.pluralizationRules = {
|
||||||
|
|
||||||
// Set current locale to null
|
// Set current locale to null
|
||||||
I18n.locale = null;
|
I18n.locale = null;
|
||||||
|
I18n.fallbackLocale = null;
|
||||||
|
|
||||||
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
|
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
|
||||||
I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
|
I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
|
||||||
|
@ -143,6 +144,10 @@ I18n.translate = function(scope, options) {
|
||||||
var translation = this.lookup(scope, options);
|
var translation = this.lookup(scope, options);
|
||||||
|
|
||||||
if (!this.noFallbacks) {
|
if (!this.noFallbacks) {
|
||||||
|
if (!translation && this.fallbackLocale) {
|
||||||
|
options.locale = this.fallbackLocale;
|
||||||
|
translation = this.lookup(scope, options);
|
||||||
|
}
|
||||||
if (!translation && this.currentLocale() !== this.defaultLocale) {
|
if (!translation && this.currentLocale() !== this.defaultLocale) {
|
||||||
options.locale = this.defaultLocale;
|
options.locale = this.defaultLocale;
|
||||||
translation = this.lookup(scope, options);
|
translation = this.lookup(scope, options);
|
||||||
|
|
|
@ -7,9 +7,12 @@ class LocaleSiteSetting < EnumSiteSetting
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.values
|
def self.values
|
||||||
supported_locales.map do |l|
|
@values ||= supported_locales.map do |locale|
|
||||||
lang = language_names[l] || language_names[l[0..1]]
|
lang = language_names[locale] || language_names[locale.split("_")[0]]
|
||||||
{ name: lang ? lang['nativeName'] : l, value: l }
|
{
|
||||||
|
name: lang ? lang['nativeName'] : locale,
|
||||||
|
value: locale
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -19,43 +22,41 @@ class LocaleSiteSetting < EnumSiteSetting
|
||||||
return @language_names if @language_names
|
return @language_names if @language_names
|
||||||
|
|
||||||
@lock.synchronize do
|
@lock.synchronize do
|
||||||
@language_names ||= YAML.load(File.read(File.join(Rails.root, 'config', 'locales', 'names.yml')))
|
@language_names ||= begin
|
||||||
|
names = YAML.load(File.read(File.join(Rails.root, 'config', 'locales', 'names.yml')))
|
||||||
|
|
||||||
|
DiscoursePluginRegistry.locales.each do |locale, options|
|
||||||
|
if !names.key?(locale) && options[:name] && options[:nativeName]
|
||||||
|
names[locale] = { "name" => options[:name], "nativeName" => options[:nativeName] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
names
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.supported_locales
|
def self.supported_locales
|
||||||
@lock.synchronize do
|
@lock.synchronize do
|
||||||
@supported_locales ||= begin
|
@supported_locales ||= begin
|
||||||
app_client_files = Dir.glob(
|
locales = Dir.glob(
|
||||||
File.join(Rails.root, 'config', 'locales', 'client.*.yml')
|
File.join(Rails.root, 'config', 'locales', 'client.*.yml')
|
||||||
)
|
).map { |x| x.split('.')[-2] }
|
||||||
|
|
||||||
unless ignore_plugins?
|
locales += DiscoursePluginRegistry.locales.keys
|
||||||
app_client_files += Dir.glob(
|
locales.uniq.sort
|
||||||
File.join(Rails.root, 'plugins', '*', 'config', 'locales', 'client.*.yml')
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
app_client_files.map { |x| x.split('.')[-2] }
|
|
||||||
.uniq
|
|
||||||
.select { |locale| valid_locale?(locale) }
|
|
||||||
.sort
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.valid_locale?(locale)
|
def self.reset!
|
||||||
assets = Rails.configuration.assets
|
@lock.synchronize do
|
||||||
|
@values = @language_names = @supported_locales = nil
|
||||||
assets.precompile.grep(/locales\/#{locale}(?:\.js)?/).present? &&
|
end
|
||||||
(Dir.glob(File.join(Rails.root, 'app', 'assets', 'javascripts', 'locales', "#{locale}.js.erb")).present? ||
|
|
||||||
Dir.glob(File.join(Rails.root, 'plugins', '*', 'assets', 'locales', "#{locale}.js.erb")).present?)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ignore_plugins?
|
def self.fallback_locale(locale)
|
||||||
Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
|
plugin_locale = DiscoursePluginRegistry.locales[locale.to_s]
|
||||||
|
plugin_locale ? plugin_locale[:fallbackLocale]&.to_sym : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
private_class_method :valid_locale?
|
|
||||||
private_class_method :ignore_plugins?
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,8 @@ class TranslationOverride < ActiveRecord::Base
|
||||||
|
|
||||||
data = { value: value }
|
data = { value: value }
|
||||||
if key.end_with?('_MF')
|
if key.end_with?('_MF')
|
||||||
data[:compiled_js] = JsLocaleHelper.compile_message_format(locale, value)
|
_, filename = JsLocaleHelper.find_message_format_locale(['en'], false)
|
||||||
|
data[:compiled_js] = JsLocaleHelper.compile_message_format(filename, locale, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
translation_override = find_or_initialize_by(params)
|
translation_override = find_or_initialize_by(params)
|
||||||
|
|
|
@ -119,9 +119,6 @@ eo:
|
||||||
es:
|
es:
|
||||||
name: Spanish
|
name: Spanish
|
||||||
nativeName: Español
|
nativeName: Español
|
||||||
es_MX:
|
|
||||||
name: Spanish
|
|
||||||
nativeName: Español (MX)
|
|
||||||
et:
|
et:
|
||||||
name: Estonian
|
name: Estonian
|
||||||
nativeName: eesti
|
nativeName: eesti
|
||||||
|
|
|
@ -14,6 +14,7 @@ class DiscoursePluginRegistry
|
||||||
attr_writer :handlebars
|
attr_writer :handlebars
|
||||||
attr_writer :serialized_current_user_fields
|
attr_writer :serialized_current_user_fields
|
||||||
attr_writer :seed_data
|
attr_writer :seed_data
|
||||||
|
attr_writer :locales
|
||||||
attr_accessor :custom_html
|
attr_accessor :custom_html
|
||||||
|
|
||||||
def plugins
|
def plugins
|
||||||
|
@ -65,6 +66,10 @@ class DiscoursePluginRegistry
|
||||||
@seed_data ||= HashWithIndifferentAccess.new({})
|
@seed_data ||= HashWithIndifferentAccess.new({})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def locales
|
||||||
|
@locales ||= HashWithIndifferentAccess.new({})
|
||||||
|
end
|
||||||
|
|
||||||
def html_builders
|
def html_builders
|
||||||
@html_builders ||= {}
|
@html_builders ||= {}
|
||||||
end
|
end
|
||||||
|
@ -92,6 +97,10 @@ class DiscoursePluginRegistry
|
||||||
self.class.stylesheets << filename
|
self.class.stylesheets << filename
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.register_locale(locale, options = {})
|
||||||
|
self.locales[locale] = options
|
||||||
|
end
|
||||||
|
|
||||||
def register_archetype(name, options = {})
|
def register_archetype(name, options = {})
|
||||||
Archetype.register(name, options)
|
Archetype.register(name, options)
|
||||||
end
|
end
|
||||||
|
@ -171,6 +180,10 @@ class DiscoursePluginRegistry
|
||||||
result.uniq
|
result.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def locales
|
||||||
|
self.class.locales
|
||||||
|
end
|
||||||
|
|
||||||
def javascripts
|
def javascripts
|
||||||
self.class.javascripts
|
self.class.javascripts
|
||||||
end
|
end
|
||||||
|
@ -207,6 +220,7 @@ class DiscoursePluginRegistry
|
||||||
self.desktop_stylesheets = nil
|
self.desktop_stylesheets = nil
|
||||||
self.sass_variables = nil
|
self.sass_variables = nil
|
||||||
self.handlebars = nil
|
self.handlebars = nil
|
||||||
|
self.locales = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.reset!
|
def self.reset!
|
||||||
|
@ -222,6 +236,7 @@ class DiscoursePluginRegistry
|
||||||
html_builders.clear
|
html_builders.clear
|
||||||
vendored_pretty_text.clear
|
vendored_pretty_text.clear
|
||||||
seed_path_builders.clear
|
seed_path_builders.clear
|
||||||
|
locales.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.setup(plugin_class)
|
def self.setup(plugin_class)
|
||||||
|
|
|
@ -39,6 +39,13 @@ module I18n
|
||||||
if @loaded_locales.empty?
|
if @loaded_locales.empty?
|
||||||
# load all rb files
|
# load all rb files
|
||||||
I18n.backend.load_translations(I18n.load_path.grep(/\.rb$/))
|
I18n.backend.load_translations(I18n.load_path.grep(/\.rb$/))
|
||||||
|
|
||||||
|
# load plural rules from plugins
|
||||||
|
DiscoursePluginRegistry.locales.each do |locale, options|
|
||||||
|
if options[:plural]
|
||||||
|
I18n.backend.store_translations(locale, i18n: { plural: options[:plural] })
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# load it
|
# load it
|
||||||
|
|
|
@ -3,7 +3,8 @@ module I18n
|
||||||
# Configure custom fallback order
|
# Configure custom fallback order
|
||||||
class FallbackLocaleList < Hash
|
class FallbackLocaleList < Hash
|
||||||
def [](locale)
|
def [](locale)
|
||||||
[locale, SiteSetting.default_locale.to_sym, :en].uniq.compact
|
fallback_locale = LocaleSiteSetting.fallback_locale(locale)
|
||||||
|
[locale, fallback_locale, SiteSetting.default_locale.to_sym, :en].uniq.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -85,6 +85,7 @@ module JsLocaleHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load_translations_merged(*locales)
|
def self.load_translations_merged(*locales)
|
||||||
|
locales = locales.compact
|
||||||
@loaded_merges ||= {}
|
@loaded_merges ||= {}
|
||||||
@loaded_merges[locales.join('-')] ||= begin
|
@loaded_merges[locales.join('-')] ||= begin
|
||||||
all_translations = {}
|
all_translations = {}
|
||||||
|
@ -104,6 +105,7 @@ module JsLocaleHelper
|
||||||
current_locale = I18n.locale
|
current_locale = I18n.locale
|
||||||
locale_sym = locale_str.to_sym
|
locale_sym = locale_str.to_sym
|
||||||
site_locale = SiteSetting.default_locale.to_sym
|
site_locale = SiteSetting.default_locale.to_sym
|
||||||
|
fallback_locale = LocaleSiteSetting.fallback_locale(locale_str)
|
||||||
|
|
||||||
I18n.locale = locale_sym
|
I18n.locale = locale_sym
|
||||||
|
|
||||||
|
@ -113,9 +115,9 @@ module JsLocaleHelper
|
||||||
elsif locale_sym == :en
|
elsif locale_sym == :en
|
||||||
load_translations(locale_sym)
|
load_translations(locale_sym)
|
||||||
elsif locale_sym == site_locale || site_locale == :en
|
elsif locale_sym == site_locale || site_locale == :en
|
||||||
load_translations_merged(locale_sym, :en)
|
load_translations_merged(locale_sym, fallback_locale, :en)
|
||||||
else
|
else
|
||||||
load_translations_merged(locale_sym, site_locale, :en)
|
load_translations_merged(locale_sym, fallback_locale, site_locale, :en)
|
||||||
end
|
end
|
||||||
|
|
||||||
I18n.locale = current_locale
|
I18n.locale = current_locale
|
||||||
|
@ -125,11 +127,13 @@ module JsLocaleHelper
|
||||||
|
|
||||||
def self.output_locale(locale)
|
def self.output_locale(locale)
|
||||||
locale_str = locale.to_s
|
locale_str = locale.to_s
|
||||||
|
fallback_locale_str = LocaleSiteSetting.fallback_locale(locale_str)&.to_s
|
||||||
translations = Marshal.load(Marshal.dump(translations_for(locale_str)))
|
translations = Marshal.load(Marshal.dump(translations_for(locale_str)))
|
||||||
|
|
||||||
message_formats = strip_out_message_formats!(translations[locale_str]['js'])
|
message_formats = strip_out_message_formats!(translations[locale_str]['js'])
|
||||||
message_formats.merge!(strip_out_message_formats!(translations[locale_str]['admin_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.keys.each do |l|
|
||||||
translations[l].keys.each do |k|
|
translations[l].keys.each do |k|
|
||||||
|
@ -140,7 +144,8 @@ module JsLocaleHelper
|
||||||
# I18n
|
# I18n
|
||||||
result << "I18n.translations = #{translations.to_json};\n"
|
result << "I18n.translations = #{translations.to_json};\n"
|
||||||
result << "I18n.locale = '#{locale_str}';\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
|
# moment
|
||||||
result << File.read("#{Rails.root}/lib/javascripts/moment.js")
|
result << File.read("#{Rails.root}/lib/javascripts/moment.js")
|
||||||
|
@ -150,6 +155,41 @@ module JsLocaleHelper
|
||||||
result
|
result
|
||||||
end
|
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
|
def self.moment_formats
|
||||||
result = ""
|
result = ""
|
||||||
result << moment_format_function('short_date_no_year')
|
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"
|
"moment.fn.#{name.camelize(:lower)} = function(){ return this.format('#{format}'); };\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.moment_locale(locale_str)
|
def self.moment_locale(locale)
|
||||||
# moment.js uses a different naming scheme for locale files
|
_, filename = find_moment_locale([locale])
|
||||||
locale_str = locale_str.tr('_', '-').downcase
|
filename && File.exist?(filename) ? File.read(filename) << "\n" : ""
|
||||||
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" : ""
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.generate_message_format(message_formats, locale_str)
|
def self.generate_message_format(message_formats, locale, filename)
|
||||||
formats = message_formats.map { |k, v| k.inspect << " : " << compile_message_format(locale_str, v) }.join(", ")
|
formats = message_formats.map { |k, v| k.inspect << " : " << compile_message_format(filename, locale, v) }.join(", ")
|
||||||
|
|
||||||
filename = "#{Rails.root}/lib/javascripts/locale/#{locale_str}.js"
|
|
||||||
filename = "#{Rails.root}/lib/javascripts/locale/en.js" unless File.exists?(filename)
|
|
||||||
|
|
||||||
result = "MessageFormat = {locale: {}};\n"
|
result = "MessageFormat = {locale: {}};\n"
|
||||||
result << "I18n._compiledMFs = {#{formats}};\n"
|
result << "I18n._compiledMFs = {#{formats}};\n"
|
||||||
|
@ -203,10 +233,9 @@ module JsLocaleHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.compile_message_format(locale, format)
|
def self.compile_message_format(path, locale, format)
|
||||||
with_context do |ctx|
|
with_context do |ctx|
|
||||||
path = "#{Rails.root}/lib/javascripts/locale/#{locale}.js"
|
ctx.load(path) if File.exist?(path)
|
||||||
ctx.load(path) if File.exists?(path)
|
|
||||||
ctx.eval("mf = new MessageFormat('#{locale}');")
|
ctx.eval("mf = new MessageFormat('#{locale}');")
|
||||||
ctx.eval("mf.precompile(mf.parse(#{format.inspect}))")
|
ctx.eval("mf.precompile(mf.parse(#{format.inspect}))")
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Plugin::Instance
|
||||||
:color_schemes,
|
:color_schemes,
|
||||||
:initializers,
|
:initializers,
|
||||||
:javascripts,
|
:javascripts,
|
||||||
|
:locales,
|
||||||
:service_workers,
|
:service_workers,
|
||||||
:styles,
|
:styles,
|
||||||
:themes].each do |att|
|
:themes].each do |att|
|
||||||
|
@ -319,6 +320,14 @@ class Plugin::Instance
|
||||||
javascripts << js
|
javascripts << js
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @option opts [String] :name
|
||||||
|
# @option opts [String] :nativeName
|
||||||
|
# @option opts [String] :fallbackLocale
|
||||||
|
# @option opts [Hash] :plural
|
||||||
|
def register_locale(locale, opts = {})
|
||||||
|
locales << [locale, opts]
|
||||||
|
end
|
||||||
|
|
||||||
def register_custom_html(hash)
|
def register_custom_html(hash)
|
||||||
DiscoursePluginRegistry.custom_html ||= {}
|
DiscoursePluginRegistry.custom_html ||= {}
|
||||||
DiscoursePluginRegistry.custom_html.merge!(hash)
|
DiscoursePluginRegistry.custom_html.merge!(hash)
|
||||||
|
@ -427,7 +436,7 @@ JS
|
||||||
end
|
end
|
||||||
|
|
||||||
register_assets! unless assets.blank?
|
register_assets! unless assets.blank?
|
||||||
|
register_locales!
|
||||||
register_service_workers!
|
register_service_workers!
|
||||||
|
|
||||||
seed_data.each do |key, value|
|
seed_data.each do |key, value|
|
||||||
|
@ -532,6 +541,33 @@ JS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def register_locales!
|
||||||
|
root_path = File.dirname(@path)
|
||||||
|
|
||||||
|
locales.each do |locale, opts|
|
||||||
|
opts = opts.dup
|
||||||
|
opts[:client_locale_file] = File.join(root_path, "config/locales/client.#{locale}.yml")
|
||||||
|
opts[:server_locale_file] = File.join(root_path, "config/locales/server.#{locale}.yml")
|
||||||
|
opts[:js_locale_file] = File.join(root_path, "assets/locales/#{locale}.js.erb")
|
||||||
|
|
||||||
|
locale_chain = opts[:fallbackLocale] ? [locale, opts[:fallbackLocale]] : [locale]
|
||||||
|
lib_locale_path = File.join(root_path, "lib/javascripts/locale")
|
||||||
|
|
||||||
|
path = File.join(lib_locale_path, "message_format")
|
||||||
|
opts[:message_format] = find_locale_file(locale_chain, path)
|
||||||
|
opts[:message_format] = JsLocaleHelper.find_message_format_locale(locale_chain, false) unless opts[:message_format]
|
||||||
|
|
||||||
|
path = File.join(lib_locale_path, "moment_js")
|
||||||
|
opts[:moment_js] = find_locale_file(locale_chain, path)
|
||||||
|
opts[:moment_js] = JsLocaleHelper.find_moment_locale(locale_chain) unless opts[:moment_js]
|
||||||
|
|
||||||
|
if valid_locale?(opts)
|
||||||
|
DiscoursePluginRegistry.register_locale(locale, opts)
|
||||||
|
Rails.configuration.assets.precompile << "locales/#{locale}.js"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def write_asset(path, contents)
|
def write_asset(path, contents)
|
||||||
|
@ -553,4 +589,18 @@ JS
|
||||||
yield plugin
|
yield plugin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_locale?(custom_locale)
|
||||||
|
File.exist?(custom_locale[:client_locale_file]) &&
|
||||||
|
File.exist?(custom_locale[:server_locale_file]) &&
|
||||||
|
File.exist?(custom_locale[:js_locale_file]) &&
|
||||||
|
custom_locale[:message_format] && custom_locale[:moment_js]
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_locale_file(locale_chain, path)
|
||||||
|
locale_chain.each do |locale|
|
||||||
|
filename = File.join(path, "#{locale}.js")
|
||||||
|
return [locale, filename] if File.exist?(filename)
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
48
spec/components/fallback_locale_list_spec.rb
Normal file
48
spec/components/fallback_locale_list_spec.rb
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
require 'i18n/backend/fallback_locale_list'
|
||||||
|
|
||||||
|
describe I18n::Backend::FallbackLocaleList do
|
||||||
|
let(:list) { I18n::Backend::FallbackLocaleList.new }
|
||||||
|
|
||||||
|
it "works when default_locale is English" do
|
||||||
|
SiteSetting.default_locale = :en
|
||||||
|
|
||||||
|
expect(list[:ru]).to eq([:ru, :en])
|
||||||
|
expect(list[:en]).to eq([:en])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works when default_locale is not English" do
|
||||||
|
SiteSetting.default_locale = :de
|
||||||
|
|
||||||
|
expect(list[:ru]).to eq([:ru, :de, :en])
|
||||||
|
expect(list[:de]).to eq([:de, :en])
|
||||||
|
expect(list[:en]).to eq([:en, :de])
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when plugin registered fallback locale" do
|
||||||
|
before do
|
||||||
|
DiscoursePluginRegistry.register_locale("es_MX", fallbackLocale: "es")
|
||||||
|
DiscoursePluginRegistry.register_locale("de_AT", fallbackLocale: "de")
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
DiscoursePluginRegistry.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works when default_locale is English" do
|
||||||
|
SiteSetting.default_locale = :en
|
||||||
|
|
||||||
|
expect(list[:de_AT]).to eq([:de_AT, :de, :en])
|
||||||
|
expect(list[:de]).to eq([:de, :en])
|
||||||
|
expect(list[:en]).to eq([:en])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works when default_locale is not English" do
|
||||||
|
SiteSetting.default_locale = :de
|
||||||
|
|
||||||
|
expect(list[:es_MX]).to eq([:es_MX, :es, :de, :en])
|
||||||
|
expect(list[:es]).to eq([:es, :de, :en])
|
||||||
|
expect(list[:en]).to eq([:en, :de])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,9 @@
|
||||||
require "rails_helper"
|
require "rails_helper"
|
||||||
|
|
||||||
describe "translate accelerator" do
|
describe "translate accelerator" do
|
||||||
|
after do
|
||||||
|
I18n.reload!
|
||||||
|
end
|
||||||
|
|
||||||
it "overrides for both string and symbol keys" do
|
it "overrides for both string and symbol keys" do
|
||||||
key = "user.email.not_allowed"
|
key = "user.email.not_allowed"
|
||||||
|
@ -32,4 +35,39 @@ describe "translate accelerator" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "plugins" do
|
||||||
|
before do
|
||||||
|
DiscoursePluginRegistry.register_locale(
|
||||||
|
"foo",
|
||||||
|
name: "Foo",
|
||||||
|
nativeName: "Foo Bar",
|
||||||
|
plural: {
|
||||||
|
keys: [:one, :few, :other],
|
||||||
|
rule: lambda do |n|
|
||||||
|
return :one if n == 1
|
||||||
|
return :few if n < 10
|
||||||
|
:other
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
LocaleSiteSetting.reset!
|
||||||
|
I18n.reload!
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
DiscoursePluginRegistry.reset!
|
||||||
|
LocaleSiteSetting.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads plural rules from plugins" do
|
||||||
|
I18n.backend.store_translations(:foo, items: { one: 'one item', few: 'some items', other: "%{count} items" })
|
||||||
|
I18n.locale = :foo
|
||||||
|
|
||||||
|
expect(I18n.t('i18n.plural.keys')).to eq([:one, :few, :other])
|
||||||
|
expect(I18n.t('items', count: 1)).to eq('one item')
|
||||||
|
expect(I18n.t('items', count: 3)).to eq('some items')
|
||||||
|
expect(I18n.t('items', count: 20)).to eq('20 items')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,12 +34,17 @@ describe JsLocaleHelper do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "message format" do
|
context "message format" do
|
||||||
|
def message_format_filename(locale)
|
||||||
|
Rails.root + "lib/javascripts/locale/#{locale}.js"
|
||||||
|
end
|
||||||
|
|
||||||
def setup_message_format(format)
|
def setup_message_format(format)
|
||||||
|
filename = message_format_filename('en')
|
||||||
|
compiled = JsLocaleHelper.compile_message_format(filename, 'en', format)
|
||||||
|
|
||||||
@ctx = MiniRacer::Context.new
|
@ctx = MiniRacer::Context.new
|
||||||
@ctx.eval('MessageFormat = {locale: {}};')
|
@ctx.eval('MessageFormat = {locale: {}};')
|
||||||
@ctx.load(Rails.root + 'lib/javascripts/locale/en.js')
|
@ctx.load(filename)
|
||||||
compiled = JsLocaleHelper.compile_message_format('en', format)
|
|
||||||
@ctx.eval("var test = #{compiled}")
|
@ctx.eval("var test = #{compiled}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -110,7 +115,7 @@ describe JsLocaleHelper do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'load pluralizations rules before precompile' do
|
it 'load pluralizations rules before precompile' do
|
||||||
message = JsLocaleHelper.compile_message_format('ru', 'format')
|
message = JsLocaleHelper.compile_message_format(message_format_filename('ru'), 'ru', 'format')
|
||||||
expect(message).not_to match 'Plural Function not found'
|
expect(message).not_to match 'Plural Function not found'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,8 +10,8 @@ describe Plugin::Instance do
|
||||||
context "find_all" do
|
context "find_all" do
|
||||||
it "can find plugins correctly" do
|
it "can find plugins correctly" do
|
||||||
plugins = Plugin::Instance.find_all("#{Rails.root}/spec/fixtures/plugins")
|
plugins = Plugin::Instance.find_all("#{Rails.root}/spec/fixtures/plugins")
|
||||||
expect(plugins.count).to eq(1)
|
expect(plugins.count).to eq(2)
|
||||||
plugin = plugins[0]
|
plugin = plugins[1]
|
||||||
|
|
||||||
expect(plugin.name).to eq("plugin-name")
|
expect(plugin.name).to eq("plugin-name")
|
||||||
expect(plugin.path).to eq("#{Rails.root}/spec/fixtures/plugins/my_plugin/plugin.rb")
|
expect(plugin.path).to eq("#{Rails.root}/spec/fixtures/plugins/my_plugin/plugin.rb")
|
||||||
|
@ -268,4 +268,108 @@ describe Plugin::Instance do
|
||||||
expect(called).to eq(1)
|
expect(called).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "locales" do
|
||||||
|
let(:plugin_path) { "#{Rails.root}/spec/fixtures/plugins/custom_locales" }
|
||||||
|
let!(:plugin) { Plugin::Instance.new(nil, "#{plugin_path}/plugin.rb") }
|
||||||
|
let(:plural) do
|
||||||
|
{
|
||||||
|
keys: [:one, :few, :other],
|
||||||
|
rule: lambda do |n|
|
||||||
|
return :one if n == 1
|
||||||
|
return :few if n < 10
|
||||||
|
:other
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_locale(locale, opts)
|
||||||
|
plugin.register_locale(locale, opts)
|
||||||
|
plugin.activate!
|
||||||
|
|
||||||
|
DiscoursePluginRegistry.locales[locale]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "enables the registered locales only on activate" do
|
||||||
|
plugin.register_locale("foo", name: "Foo", nativeName: "Foo Bar", plural: plural)
|
||||||
|
plugin.register_locale("es_MX", name: "Spanish (Mexico)", nativeName: "Español (México)", fallbackLocale: "es")
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(0)
|
||||||
|
|
||||||
|
plugin.activate!
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows finding the locale by string and symbol" do
|
||||||
|
register_locale("foo", name: "Foo", nativeName: "Foo Bar", plural: plural)
|
||||||
|
|
||||||
|
expect(DiscoursePluginRegistry.locales).to have_key(:foo)
|
||||||
|
expect(DiscoursePluginRegistry.locales).to have_key('foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "correctly registers a new locale" do
|
||||||
|
locale = register_locale("foo", name: "Foo", nativeName: "Foo Bar", plural: plural)
|
||||||
|
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(1)
|
||||||
|
expect(DiscoursePluginRegistry.locales).to have_key(:foo)
|
||||||
|
|
||||||
|
expect(locale[:fallbackLocale]).to be_nil
|
||||||
|
expect(locale[:message_format]).to eq(["foo", "#{plugin_path}/lib/javascripts/locale/message_format/foo.js"])
|
||||||
|
expect(locale[:moment_js]).to eq(["foo", "#{plugin_path}/lib/javascripts/locale/moment_js/foo.js"])
|
||||||
|
expect(locale[:plural]).to eq(plural.with_indifferent_access)
|
||||||
|
|
||||||
|
expect(Rails.configuration.assets.precompile).to include("locales/foo.js")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "correctly registers a new locale using a fallback locale" do
|
||||||
|
locale = register_locale("es_MX", name: "Spanish (Mexico)", nativeName: "Español (México)", fallbackLocale: "es")
|
||||||
|
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(1)
|
||||||
|
expect(DiscoursePluginRegistry.locales).to have_key(:es_MX)
|
||||||
|
|
||||||
|
expect(locale[:fallbackLocale]).to eq("es")
|
||||||
|
expect(locale[:message_format]).to eq(["es", "#{Rails.root}/lib/javascripts/locale/es.js"])
|
||||||
|
expect(locale[:moment_js]).to eq(["es", "#{Rails.root}/lib/javascripts/moment_locale/es.js"])
|
||||||
|
expect(locale[:plural]).to be_nil
|
||||||
|
|
||||||
|
expect(Rails.configuration.assets.precompile).to include("locales/es_MX.js")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "correctly registers a new locale when some files exist in core" do
|
||||||
|
locale = register_locale("tlh", name: "Klingon", nativeName: "tlhIngan Hol", plural: plural)
|
||||||
|
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(1)
|
||||||
|
expect(DiscoursePluginRegistry.locales).to have_key(:tlh)
|
||||||
|
|
||||||
|
expect(locale[:fallbackLocale]).to be_nil
|
||||||
|
expect(locale[:message_format]).to eq(["tlh", "#{plugin_path}/lib/javascripts/locale/message_format/tlh.js"])
|
||||||
|
expect(locale[:moment_js]).to eq(["tlh", "#{Rails.root}/lib/javascripts/moment_locale/tlh.js"])
|
||||||
|
expect(locale[:plural]).to eq(plural.with_indifferent_access)
|
||||||
|
|
||||||
|
expect(Rails.configuration.assets.precompile).to include("locales/tlh.js")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not register a new locale when the fallback locale does not exist" do
|
||||||
|
register_locale("bar", name: "Bar", nativeName: "Bar", fallbackLocale: "foo")
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
[
|
||||||
|
"config/locales/client.foo.yml",
|
||||||
|
"config/locales/server.foo.yml",
|
||||||
|
"lib/javascripts/locale/message_format/foo.js",
|
||||||
|
"lib/javascripts/locale/moment_js/foo.js",
|
||||||
|
"assets/locales/foo.js.erb"
|
||||||
|
].each do |path|
|
||||||
|
it "does not register a new locale when #{path} is missing" do
|
||||||
|
path = "#{plugin_path}/#{path}"
|
||||||
|
File.stubs('exist?').returns(false)
|
||||||
|
File.stubs('exist?').with(regexp_matches(/#{Regexp.quote(plugin_path)}.*/)).returns(true)
|
||||||
|
File.stubs('exist?').with(path).returns(false)
|
||||||
|
|
||||||
|
register_locale("foo", name: "Foo", nativeName: "Foo Bar", plural: plural)
|
||||||
|
expect(DiscoursePluginRegistry.locales.count).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
2
spec/fixtures/plugins/custom_locales/assets/locales/es_MX.js.erb
vendored
Normal file
2
spec/fixtures/plugins/custom_locales/assets/locales/es_MX.js.erb
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//= require locales/i18n
|
||||||
|
<%= JsLocaleHelper.output_locale(:es_MX) %>
|
2
spec/fixtures/plugins/custom_locales/assets/locales/foo.js.erb
vendored
Normal file
2
spec/fixtures/plugins/custom_locales/assets/locales/foo.js.erb
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//= require locales/i18n
|
||||||
|
<%= JsLocaleHelper.output_locale(:foo) %>
|
2
spec/fixtures/plugins/custom_locales/assets/locales/tlh.js.erb
vendored
Normal file
2
spec/fixtures/plugins/custom_locales/assets/locales/tlh.js.erb
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//= require locales/i18n
|
||||||
|
<%= JsLocaleHelper.output_locale(:tlh) %>
|
1
spec/fixtures/plugins/custom_locales/config/locales/client.es_MX.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/client.es_MX.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
es_MX:
|
1
spec/fixtures/plugins/custom_locales/config/locales/client.foo.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/client.foo.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
foo:
|
1
spec/fixtures/plugins/custom_locales/config/locales/client.tlh.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/client.tlh.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
tlh:
|
1
spec/fixtures/plugins/custom_locales/config/locales/server.es_MX.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/server.es_MX.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
es_MX:
|
1
spec/fixtures/plugins/custom_locales/config/locales/server.foo.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/server.foo.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
foo:
|
1
spec/fixtures/plugins/custom_locales/config/locales/server.tlh.yml
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/config/locales/server.tlh.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
tlh:
|
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/message_format/foo.js
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/message_format/foo.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// this file should contain plural rules
|
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/message_format/tlh.js
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/message_format/tlh.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// this file should contain plural rules
|
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/moment_js/foo.js
vendored
Normal file
1
spec/fixtures/plugins/custom_locales/lib/javascripts/locale/moment_js/foo.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// this file should contain the locale configuration for moment.js
|
4
spec/fixtures/plugins/custom_locales/plugin.rb
vendored
Normal file
4
spec/fixtures/plugins/custom_locales/plugin.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# name: custom-locales
|
||||||
|
# about: Fixtures for plugin that adds new locales
|
||||||
|
# version: 1.0
|
||||||
|
# authors: Gerhard Schlager
|
|
@ -1,6 +1,15 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe LocaleSiteSetting do
|
describe LocaleSiteSetting do
|
||||||
|
def core_locales
|
||||||
|
pattern = File.join(Rails.root, 'config', 'locales', 'client.*.yml')
|
||||||
|
Dir.glob(pattern).map { |x| x.split('.')[-2] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def native_locale_name(locale)
|
||||||
|
value = LocaleSiteSetting.values.find { |v| v[:value] == locale }
|
||||||
|
value[:name]
|
||||||
|
end
|
||||||
|
|
||||||
describe 'valid_value?' do
|
describe 'valid_value?' do
|
||||||
it 'returns true for a locale that we have translations for' do
|
it 'returns true for a locale that we have translations for' do
|
||||||
|
@ -14,8 +23,69 @@ describe LocaleSiteSetting do
|
||||||
|
|
||||||
describe 'values' do
|
describe 'values' do
|
||||||
it 'returns all the locales that we have translations for' do
|
it 'returns all the locales that we have translations for' do
|
||||||
expect(LocaleSiteSetting.values.map { |x| x[:value] }).to include(*Dir.glob(File.join(Rails.root, 'config', 'locales', 'client.*.yml')).map { |x| x.split('.')[-2] })
|
expect(LocaleSiteSetting.values.map { |x| x[:value] }).to include(*core_locales)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns native names' do
|
||||||
|
expect(native_locale_name('de')).to eq('Deutsch')
|
||||||
|
expect(native_locale_name('zh_CN')).to eq('中文')
|
||||||
|
expect(native_locale_name('zh_TW')).to eq('中文 (TW)')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with locales from plugin' do
|
||||||
|
before do
|
||||||
|
DiscoursePluginRegistry.register_locale("foo", name: "Foo", nativeName: "Native Foo")
|
||||||
|
DiscoursePluginRegistry.register_locale("bar", name: "Bar", nativeName: "Native Bar")
|
||||||
|
DiscoursePluginRegistry.register_locale("de", name: "Renamed German", nativeName: "Native renamed German")
|
||||||
|
DiscoursePluginRegistry.register_locale("de_AT", name: "German (Austria)", nativeName: "Österreichisch", fallbackLocale: "de")
|
||||||
|
DiscoursePluginRegistry.register_locale("tlh")
|
||||||
|
|
||||||
|
# Plugins normally register a locale before LocaleSiteSetting is initialized.
|
||||||
|
# That's not happening in tests, so we need to call reset!
|
||||||
|
LocaleSiteSetting.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
DiscoursePluginRegistry.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'valid_value?' do
|
||||||
|
it 'returns true for locales from core' do
|
||||||
|
expect(LocaleSiteSetting.valid_value?('en')).to eq(true)
|
||||||
|
expect(LocaleSiteSetting.valid_value?('de')).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true for locales added by plugins' do
|
||||||
|
expect(LocaleSiteSetting.valid_value?('foo')).to eq(true)
|
||||||
|
expect(LocaleSiteSetting.valid_value?('bar')).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'values' do
|
||||||
|
it 'returns native names added by plugin' do
|
||||||
|
expect(native_locale_name('foo')).to eq('Native Foo')
|
||||||
|
expect(native_locale_name('bar')).to eq('Native Bar')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not allow plugins to override native names that exist in core' do
|
||||||
|
expect(native_locale_name('de')).to eq('Deutsch')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the language code when no nativeName is set' do
|
||||||
|
expect(native_locale_name('tlh')).to eq('tlh')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'fallback_locale' do
|
||||||
|
it 'returns the fallback locale registered by plugin' do
|
||||||
|
expect(LocaleSiteSetting.fallback_locale('de_AT')).to eq(:de)
|
||||||
|
expect(LocaleSiteSetting.fallback_locale(:de_AT)).to eq(:de)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns nothing when no fallback locale was registered' do
|
||||||
|
expect(LocaleSiteSetting.fallback_locale('foo')).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,17 +1,30 @@
|
||||||
QUnit.module("lib:i18n", {
|
QUnit.module("lib:i18n", {
|
||||||
_locale: I18n.locale,
|
_locale: I18n.locale,
|
||||||
|
_fallbackLocale: I18n.fallbackLocale,
|
||||||
_translations: I18n.translations,
|
_translations: I18n.translations,
|
||||||
|
|
||||||
beforeEach() {
|
beforeEach() {
|
||||||
I18n.locale = "fr";
|
I18n.locale = "fr";
|
||||||
|
|
||||||
I18n.translations = {
|
I18n.translations = {
|
||||||
|
"fr_FOO": {
|
||||||
|
"js": {
|
||||||
|
"topic": {
|
||||||
|
"reply": {
|
||||||
|
"title": "Foo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
"js": {
|
"js": {
|
||||||
"hello": "Bonjour",
|
"hello": "Bonjour",
|
||||||
"topic": {
|
"topic": {
|
||||||
"reply": {
|
"reply": {
|
||||||
"title": "Répondre",
|
"title": "Répondre"
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Partager"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"character_count": {
|
"character_count": {
|
||||||
|
@ -56,6 +69,7 @@ QUnit.module("lib:i18n", {
|
||||||
|
|
||||||
afterEach() {
|
afterEach() {
|
||||||
I18n.locale = this._locale;
|
I18n.locale = this._locale;
|
||||||
|
I18n.fallbackLocale = this._fallbackLocale;
|
||||||
I18n.translations = this._translations;
|
I18n.translations = this._translations;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -93,3 +107,12 @@ QUnit.test("pluralizations", assert => {
|
||||||
assert.equal(I18n.t("word_count", { count: 10 }), "10 words");
|
assert.equal(I18n.t("word_count", { count: 10 }), "10 words");
|
||||||
assert.equal(I18n.t("word_count", { count: 100 }), "100 words");
|
assert.equal(I18n.t("word_count", { count: 100 }), "100 words");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QUnit.test("fallback", assert => {
|
||||||
|
I18n.locale = "fr_FOO";
|
||||||
|
I18n.fallbackLocale = "fr";
|
||||||
|
|
||||||
|
assert.equal(I18n.t("topic.reply.title"), "Foo", "uses locale translations when they exist");
|
||||||
|
assert.equal(I18n.t("topic.share.title"), "Partager", "falls back to fallbackLocale translations when they exist");
|
||||||
|
assert.equal(I18n.t("topic.reply.help"), "begin composing a reply to this topic", "falls back to English translations");
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user