Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'rake'
gem 'bcrypt-ruby'
gem 'eventmachine', '~> 1.0.0'
gem 'fog'
gem 'i18n'
gem 'nokogiri', '~> 1.6.2'
gem 'unf'
gem 'netaddr'
Expand Down
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ DEPENDENCIES
fakefs
fog
httpclient
i18n
loggregator_emitter (~> 3.0)
machinist (~> 1.0.6)
membrane (~> 1.0)
Expand Down
1 change: 1 addition & 0 deletions app/controllers/base/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def inject_dependencies(dependencies = {})
# body string], or just a body string.
def dispatch(op, *args)
logger.debug "cc.dispatch", endpoint: op, args: args
I18n.locale = env['HTTP_ACCEPT_LANGUAGE']
check_authentication(op)
send(op, *args)
rescue Sequel::ValidationFailed => e
Expand Down
3 changes: 3 additions & 0 deletions lib/cloud_controller/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class Config < VCAP::Config
],

optional(:app_bits_upload_grace_period_in_seconds) => Integer,

optional(:default_locale) => String
}
end

Expand Down Expand Up @@ -235,6 +237,7 @@ def merge_defaults(config)
config[:billing_event_writing_enabled] = true if config[:billing_event_writing_enabled].nil?
config[:skip_cert_verify] = false if config[:skip_cert_verify].nil?
config[:app_bits_upload_grace_period_in_seconds] ||= 0
config[:default_locale] ||= "en_US"
sanitize(config)
end

Expand Down
10 changes: 10 additions & 0 deletions lib/cloud_controller/runner.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require "steno"
require "optparse"
require "i18n"
require "i18n/backend/fallbacks"
require "vcap/uaa_token_decoder"
require "vcap/uaa_verification_key"
require "cf_message_bus/message_bus"
Expand All @@ -26,10 +28,18 @@ def initialize(argv)
@config_file = File.expand_path("../../../config/cloud_controller.yml", __FILE__)
parse_options!
parse_config

init_i18n

@log_counter = Steno::Sink::Counter.new
end

def init_i18n
I18n.default_locale = @config[:default_locale]
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
I18n.load_path = Dir[File.expand_path("../../../vendor/errors/i18n/*.yml", __FILE__)]
end

def logger
@logger ||= Steno.logger("cc.runner")
end
Expand Down
7 changes: 6 additions & 1 deletion lib/vcap/errors/api_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ def message
formatted_args = args.map do |arg|
(arg.is_a? Array) ? arg.map(&:to_s).join(', ') : arg.to_s
end
sprintf(details.message_format, *formatted_args)

begin
sprintf(I18n.translate(details.name, raise: true, :locale => I18n.locale), *formatted_args)
rescue I18n::MissingTranslationData => e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine for now, but once this work is done this rescue should probably be removed so we don't accidentally have any error strings that are not in the translation files.

sprintf(details.message_format, *formatted_args)
end
end

def code
Expand Down
4 changes: 4 additions & 0 deletions spec/fixtures/i18n/en_US.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
en_US:
ServiceInvalid: "This is a translated message of %s %s."
MessagePartialTranslated: "This is a translated message of %s %s only in default locale"
3 changes: 3 additions & 0 deletions spec/fixtures/i18n/zh_CN.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
zh_CN:
ServiceInvalid: "这是一条被翻译的信息:%s %s。"
7 changes: 7 additions & 0 deletions spec/unit/controllers/base/base_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
let(:token_decoder) { double(:decoder) }
let(:header_token) { 'some token' }
let(:token_info) { {'user_id' => 'some user'} }
let(:env) { {'HTTP_ACCEPT_LANGUAGE' => 'en_US'} }

before do
configurer = VCAP::CloudController::Security::SecurityContextConfigurer.new(token_decoder)
Expand All @@ -27,6 +28,12 @@
subject.dispatch(:to_s, [:a, :b])
end

it "should record the locale during dispatching the request" do
expect(subject).to receive(:to_s).with([:a, :b])
subject.dispatch(:to_s, [:a, :b])
expect(I18n.locale).to eq(:en_US)
end

it "should log a debug message" do
expect(logger).to receive(:debug).with("cc.dispatch", endpoint: :to_s, args: [])
subject.dispatch(:to_s)
Expand Down
4 changes: 4 additions & 0 deletions spec/unit/lib/cloud_controller/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ module VCAP::CloudController
it "sets a default value for app_bits_upload_grace_period_in_seconds" do
expect(config[:app_bits_upload_grace_period_in_seconds]).to eq(0)
end

it "sets a default value for default_loacle" do
expect(config[:default_locale]).to eq("en_US")
end
end

context "when config values are provided" do
Expand Down
9 changes: 6 additions & 3 deletions spec/unit/lib/cloud_controller/runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ module VCAP::CloudController
let (:argv_options) { [] }

before do
allow_any_instance_of(Runner).to receive(:parse_config)
allow_any_instance_of(Runner).to receive(:deprecation_warning)
end

Expand All @@ -290,10 +289,10 @@ module VCAP::CloudController
describe "Configuration File" do
["-c", "--config"].each do |flag|
describe flag do
let (:argv_options) { [flag, "config/minimal_config.yml"] }
let (:argv_options) { [flag, config_file.path] }

it "should set the configuration file" do
expect(subject.config_file).to eq("config/minimal_config.yml")
expect(subject.config_file).to eq(config_file.path)
end
end
end
Expand All @@ -318,6 +317,10 @@ module VCAP::CloudController
end
end
end

it "should initialize the i18n framework" do
expect(I18n.default_locale).to eq(:en_US)
end
end

describe "#start_thin_server" do
Expand Down
63 changes: 50 additions & 13 deletions spec/unit/lib/vcap/errors/api_error_spec.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
# coding: utf-8

require 'spec_helper'

module VCAP::Errors
describe ApiError do
let(:details) do
def create_details(message)
double(Details,
name: "ServiceInvalid",
name: message,
response_code: 400,
code: 12345,
message_format: "Before %s %s after.")
end

let(:name) { "ServiceInvalid" }
let(:messageServiceInvalid) { "ServiceInvalid" }
let(:messagePartialTranslated) { "MessagePartialTranslated"}
let(:messageNotTranslated) { "MessageNotTranslated" }
let(:args) { [ "foo", "bar" ] }

let(:messageServiceInvalidDetails) { create_details(messageServiceInvalid) }
let(:messagePartialTranslatedDetails) { create_details(messagePartialTranslated) }
let(:messageNotTranslatedDetails) { create_details(messageNotTranslated) }

I18n.default_locale = :en_US
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
I18n.load_path = Dir[File.expand_path("../../../../fixtures/i18n/*.yml", File.dirname(__FILE__))]

before do
allow(Details).to receive("new").with(name).and_return(details)
allow(Details).to receive("new").with(messageServiceInvalid).and_return(messageServiceInvalidDetails)
allow(Details).to receive("new").with(messagePartialTranslated).and_return(messagePartialTranslatedDetails)
allow(Details).to receive("new").with(messageNotTranslated).and_return(messageNotTranslatedDetails)
end

context ".new_from_details" do
let(:args) { [ "foo", "bar" ] }

subject(:api_error) { ApiError.new_from_details(name, *args) }
subject(:api_error) { ApiError.new_from_details(messageServiceInvalid, *args) }

it "returns an ApiError" do
expect(api_error).to be_a(ApiError)
Expand All @@ -29,12 +42,8 @@ module VCAP::Errors
expect(api_error).to be_a(Exception)
end

it "sets the message using the format provided in the v2.yml" do
expect(api_error.message).to eq("Before foo bar after.")
end

context "if it doesn't recognise the error from v2.yml" do
let(:name) { "What is this? I don't know?!!"}
let(:messageServiceInvalid) { "What is this? I don't know?!!"}

before do
allow(Details).to receive(:new).and_call_original
Expand All @@ -46,11 +55,39 @@ module VCAP::Errors
end
end

context "get error message" do
subject(:api_error) { ApiError.new_from_details(messageServiceInvalid, *args) }
subject(:api_error_with_partial_translation) { ApiError.new_from_details(messagePartialTranslated, *args) }
subject(:api_error_with_translation_missing) { ApiError.new_from_details(messageNotTranslated, *args) }

it "should translate the message based on the locale" do
I18n.locale = :en_US
expect(api_error.message).to eq("This is a translated message of foo bar.")
I18n.locale = :zh_CN
expect(api_error.message).to eq("这是一条被翻译的信息:foo bar。")
end

it "should use the default locale message when the message is not translated in target locale" do
I18n.locale = :zh_CN
expect(api_error_with_partial_translation.message).to eq("This is a translated message of foo bar only in default locale")
end

it "should use the default locale message when the locale is not recognized" do
I18n.locale = :unknown_locale
expect(api_error.message).to eq("This is a translated message of foo bar.")
end

it "should use the original message when the translation is missing" do
I18n.locale = :en_US
expect(api_error_with_translation_missing.message).to eq("Before foo bar after.")
end
end

context "with details" do
subject(:api_error) { ApiError.new }

before do
api_error.details = details
api_error.details = messageServiceInvalidDetails
end

it "exposes the code" do
Expand Down