2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2025-09-05 08:59:27 +08:00

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

@ -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

View file

@ -1,6 +1,9 @@
require "rails_helper"
describe "translate accelerator" do
after do
I18n.reload!
end
it "overrides for both string and symbol keys" do
key = "user.email.not_allowed"
@ -32,4 +35,39 @@ describe "translate accelerator" do
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

View file

@ -34,12 +34,17 @@ describe JsLocaleHelper do
end
context "message format" do
def message_format_filename(locale)
Rails.root + "lib/javascripts/locale/#{locale}.js"
end
def setup_message_format(format)
filename = message_format_filename('en')
compiled = JsLocaleHelper.compile_message_format(filename, 'en', format)
@ctx = MiniRacer::Context.new
@ctx.eval('MessageFormat = {locale: {}};')
@ctx.load(Rails.root + 'lib/javascripts/locale/en.js')
compiled = JsLocaleHelper.compile_message_format('en', format)
@ctx.load(filename)
@ctx.eval("var test = #{compiled}")
end
@ -110,7 +115,7 @@ describe JsLocaleHelper do
end
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'
end
end

View file

@ -10,8 +10,8 @@ describe Plugin::Instance do
context "find_all" do
it "can find plugins correctly" do
plugins = Plugin::Instance.find_all("#{Rails.root}/spec/fixtures/plugins")
expect(plugins.count).to eq(1)
plugin = plugins[0]
expect(plugins.count).to eq(2)
plugin = plugins[1]
expect(plugin.name).to eq("plugin-name")
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)
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

View file

@ -0,0 +1,2 @@
//= require locales/i18n
<%= JsLocaleHelper.output_locale(:es_MX) %>

View file

@ -0,0 +1,2 @@
//= require locales/i18n
<%= JsLocaleHelper.output_locale(:foo) %>

View file

@ -0,0 +1,2 @@
//= require locales/i18n
<%= JsLocaleHelper.output_locale(:tlh) %>

View file

@ -0,0 +1 @@
es_MX:

View file

@ -0,0 +1 @@
foo:

View file

@ -0,0 +1 @@
tlh:

View file

@ -0,0 +1 @@
es_MX:

View file

@ -0,0 +1 @@
foo:

View file

@ -0,0 +1 @@
tlh:

View file

@ -0,0 +1 @@
// this file should contain plural rules

View file

@ -0,0 +1 @@
// this file should contain plural rules

View file

@ -0,0 +1 @@
// this file should contain the locale configuration for moment.js

View file

@ -0,0 +1,4 @@
# name: custom-locales
# about: Fixtures for plugin that adds new locales
# version: 1.0
# authors: Gerhard Schlager

View file

@ -1,6 +1,15 @@
require 'rails_helper'
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
it 'returns true for a locale that we have translations for' do
@ -14,8 +23,69 @@ describe LocaleSiteSetting do
describe 'values' 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
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