From 601960f5fbe260d00b8ca7ce7fc579dc26739564 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 15 Nov 2017 15:06:53 +0100 Subject: [PATCH] Implemented issue #1171 - The ability to set the platform default language. --- .../controllers/_settings/area_item.coffee | 2 +- .../_settings/area_item_default_locale.coffee | 21 +++++++ .../controllers/widget/default_locale.coffee | 23 +++++++ .../widget/switch_back_to_user.coffee | 2 +- .../javascripts/app/lib/app_post/auth.coffee | 5 +- .../javascripts/app/lib/app_post/i18n.coffee | 18 ++++++ app/controllers/first_steps_controller.rb | 2 +- app/models/locale.rb | 2 +- app/models/text_module.rb | 4 +- app/models/transaction/clearbit_enrichment.rb | 2 +- app/models/transaction/notification.rb | 2 +- app/models/transaction/slack.rb | 2 +- app/models/translation.rb | 4 +- .../20171115000001_setting_default_locale.rb | 28 +++++++++ db/seeds/settings.rb | 19 ++++++ lib/calendar_subscriptions/tickets.rb | 24 ++++---- lib/notification_factory.rb | 2 +- lib/notification_factory/mailer.rb | 2 +- lib/notification_factory/renderer.rb | 2 +- lib/notification_factory/slack.rb | 2 +- ...tification_factory_mailer_template_test.rb | 60 +++++++++++++++++++ 21 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 app/assets/javascripts/app/controllers/_settings/area_item_default_locale.coffee create mode 100644 app/assets/javascripts/app/controllers/widget/default_locale.coffee create mode 100644 db/migrate/20171115000001_setting_default_locale.rb diff --git a/app/assets/javascripts/app/controllers/_settings/area_item.coffee b/app/assets/javascripts/app/controllers/_settings/area_item.coffee index c7db71eb3..877caeee0 100644 --- a/app/assets/javascripts/app/controllers/_settings/area_item.coffee +++ b/app/assets/javascripts/app/controllers/_settings/area_item.coffee @@ -32,7 +32,7 @@ class App.SettingsAreaItem extends App.Controller ) new App.ControllerForm( - el: @el.find('.form-item'), + el: @el.find('.form-item') model: { configure_attributes: @configure_attributes, className: '' } autofocus: false ) diff --git a/app/assets/javascripts/app/controllers/_settings/area_item_default_locale.coffee b/app/assets/javascripts/app/controllers/_settings/area_item_default_locale.coffee new file mode 100644 index 000000000..5d22c5a59 --- /dev/null +++ b/app/assets/javascripts/app/controllers/_settings/area_item_default_locale.coffee @@ -0,0 +1,21 @@ +class App.SettingsAreaItemDefaultLocale extends App.SettingsAreaItem + + render: => + + options = {} + locales = App.Locale.all() + for locale in locales + options[locale.locale] = locale.name + configure_attributes = [ + { name: 'locale_default', display: '', tag: 'searchable_select', null: false, class: 'input', options: options, default: @setting.state_current.value }, + ] + + @html App.view(@template)( + setting: @setting + ) + + new App.ControllerForm( + el: @el.find('.form-item') + model: { configure_attributes: configure_attributes, className: '' } + autofocus: false + ) diff --git a/app/assets/javascripts/app/controllers/widget/default_locale.coffee b/app/assets/javascripts/app/controllers/widget/default_locale.coffee new file mode 100644 index 000000000..db4437c30 --- /dev/null +++ b/app/assets/javascripts/app/controllers/widget/default_locale.coffee @@ -0,0 +1,23 @@ +class DefaultLocale extends App.Controller + constructor: -> + super + + check = => + + preferences = App.Session.get('preferences') + return if !preferences + return if !_.isEmpty(preferences.locale) + locale = App.i18n.get() + @ajax( + id: "i18n-set-user-#{locale}" + type: 'PUT' + url: "#{App.Config.get('api_path')}/users/preferences" + data: JSON.stringify(locale: locale) + processData: true + ) + + App.Event.bind('auth:login', (session) => + @delay(check, 3500, 'default_locale') + ) + +App.Config.set('default_locale', DefaultLocale, 'Widgets') diff --git a/app/assets/javascripts/app/controllers/widget/switch_back_to_user.coffee b/app/assets/javascripts/app/controllers/widget/switch_back_to_user.coffee index 9f5e3c526..612d9cbe4 100644 --- a/app/assets/javascripts/app/controllers/widget/switch_back_to_user.coffee +++ b/app/assets/javascripts/app/controllers/widget/switch_back_to_user.coffee @@ -47,4 +47,4 @@ class Widget extends App.ControllerWidgetOnDemand 800 ) -App.Config.set( 'switch_back_to_user', Widget, 'Widgets' ) +App.Config.set('switch_back_to_user', Widget, 'Widgets') diff --git a/app/assets/javascripts/app/lib/app_post/auth.coffee b/app/assets/javascripts/app/lib/app_post/auth.coffee index f46c8c6e3..7f95f2375 100644 --- a/app/assets/javascripts/app/lib/app_post/auth.coffee +++ b/app/assets/javascripts/app/lib/app_post/auth.coffee @@ -79,8 +79,7 @@ class App.Auth @_updateModelAttributes(data.models) # set locale - locale = window.navigator.userLanguage || window.navigator.language || 'en-us' - App.i18n.set(locale) + App.i18n.set(App.i18n.detectBrowserLocale()) # rebuild navbar with new navbar items App.Event.trigger('auth') @@ -120,7 +119,7 @@ class App.Auth if preferences && preferences.locale locale = preferences.locale if !locale - locale = window.navigator.userLanguage || window.navigator.language || 'en-us' + locale = App.i18n.detectBrowserLocale() App.i18n.set(locale) App.Event.trigger('auth:login', data.session) diff --git a/app/assets/javascripts/app/lib/app_post/i18n.coffee b/app/assets/javascripts/app/lib/app_post/i18n.coffee index 560562269..af8b5ef3d 100644 --- a/app/assets/javascripts/app/lib/app_post/i18n.coffee +++ b/app/assets/javascripts/app/lib/app_post/i18n.coffee @@ -80,6 +80,24 @@ class App.i18n _instance ?= new _i18nSingleton() _instance.mapTime + @detectBrowserLocale: -> + return 'en-us' if !window.navigator.userLanguage && !window.navigator.language + + if window.navigator.languages + allLocales = App.Locale.all() + for browserLocale in window.navigator.languages + for localAllLocale in allLocales + if browserLocale is localAllLocale.locale + return localAllLocale.locale + + for browserLocale in window.navigator.languages + browserLocale = browserLocale.substr(0, 2) + for localAllLocale in allLocales + if browserLocale is localAllLocale.alias + return localAllLocale.locale + + window.navigator.userLanguage || window.navigator.language || 'en-us' + class _i18nSingleton extends Spine.Module @include App.LogInclude diff --git a/app/controllers/first_steps_controller.rb b/app/controllers/first_steps_controller.rb index 096879693..0dd392be3 100644 --- a/app/controllers/first_steps_controller.rb +++ b/app/controllers/first_steps_controller.rb @@ -177,7 +177,7 @@ class FirstStepsController < ApplicationController original_user_id = UserInfo.current_user_id result = NotificationFactory::Mailer.template( template: 'test_ticket', - locale: agent.preferences[:locale] || 'en-us', + locale: agent.preferences[:locale] || Setting.get('locale_default') || 'en-us', objects: { agent: agent, customer: customer, diff --git a/app/models/locale.rb b/app/models/locale.rb index 4ce319646..fa597f189 100644 --- a/app/models/locale.rb +++ b/app/models/locale.rb @@ -24,7 +24,7 @@ returns # read used locales based on env, e. g. export Z_LOCALES='en-us:de-de' if ENV['Z_LOCALES'] - locales = Locale.where(active: true, locale: ENV['Z_LOCALES'].split(':') ) + locales = Locale.where(active: true, locale: ENV['Z_LOCALES'].split(':')) end locales end diff --git a/app/models/text_module.rb b/app/models/text_module.rb index b01d3a037..1cec59992 100644 --- a/app/models/text_module.rb +++ b/app/models/text_module.rb @@ -18,7 +18,7 @@ load text modules from online =end def self.load(locale, overwrite_existing_item = false) - raise 'Got no locale' if locale.empty? + raise 'Got no locale' if locale.blank? locale = locale.split(',').first.downcase # in case of accept_language header is given url = "https://i18n.zammad.com/api/v1/text_modules/#{locale}" @@ -67,7 +67,7 @@ push text_modules to online text_modules_to_push.push text_module end - return true if text_modules_to_push.empty? + return true if text_modules_to_push.blank? url = 'https://i18n.zammad.com/api/v1/text_modules/thanks_for_your_support' diff --git a/app/models/transaction/clearbit_enrichment.rb b/app/models/transaction/clearbit_enrichment.rb index b9c186e9b..e38f9a052 100644 --- a/app/models/transaction/clearbit_enrichment.rb +++ b/app/models/transaction/clearbit_enrichment.rb @@ -31,7 +31,7 @@ class Transaction::ClearbitEnrichment config = Setting.get('clearbit_config') return if !config - return if config['api_key'].empty? + return if config['api_key'].blank? user = User.lookup(id: @item[:object_id]) return if !user diff --git a/app/models/transaction/notification.rb b/app/models/transaction/notification.rb index 398426e0b..8c5a74539 100644 --- a/app/models/transaction/notification.rb +++ b/app/models/transaction/notification.rb @@ -231,7 +231,7 @@ class Transaction::Notification def human_changes(user, record) return {} if !@item[:changes] - locale = user.preferences[:locale] || 'en-us' + locale = user.preferences[:locale] || Setting.get('locale_default') || 'en-us' # only show allowed attributes attribute_list = ObjectManager::Attribute.by_object_as_hash('Ticket', user) diff --git a/app/models/transaction/slack.rb b/app/models/transaction/slack.rb index 124685618..aac7d393a 100644 --- a/app/models/transaction/slack.rb +++ b/app/models/transaction/slack.rb @@ -197,7 +197,7 @@ class Transaction::Slack return {} if !@item[:changes] user = User.find(1) - locale = user.preferences[:locale] || 'en-us' + locale = user.preferences[:locale] || Setting.get('locale_default') || 'en-us' # only show allowed attributes attribute_list = ObjectManager::Attribute.by_object_as_hash('Ticket', user) diff --git a/app/models/translation.rb b/app/models/translation.rb index 5a406a21a..dbb013345 100644 --- a/app/models/translation.rb +++ b/app/models/translation.rb @@ -65,7 +65,7 @@ push translations to online end end - return true if translations_to_push.empty? + return true if translations_to_push.blank? url = 'https://i18n.zammad.com/api/v1/translations/thanks_for_your_support' @@ -108,7 +108,7 @@ reset translations to origin # only push changed translations translations = Translation.where(locale: locale) translations.each do |translation| - if !translation.target_initial || translation.target_initial.empty? + if translation.target_initial.blank? translation.destroy elsif translation.target != translation.target_initial translation.target = translation.target_initial diff --git a/db/migrate/20171115000001_setting_default_locale.rb b/db/migrate/20171115000001_setting_default_locale.rb new file mode 100644 index 000000000..e91bbfa12 --- /dev/null +++ b/db/migrate/20171115000001_setting_default_locale.rb @@ -0,0 +1,28 @@ +class SettingDefaultLocale < ActiveRecord::Migration[5.1] + def up + + # return if it's a new setup + return if !Setting.find_by(name: 'system_init_done') + + Setting.create_if_not_exists( + title: 'Locale', + name: 'locale_default', + area: 'System::Base', + description: 'Defines the system default language.', + options: { + form: [ + { + name: 'locale_default', + } + ], + }, + state: 'en-us', + preferences: { + controller: 'SettingsAreaItemDefaultLocale', + permission: ['admin.system'], + }, + frontend: true + ) + end + +end diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb index 12b351599..decad0c72 100644 --- a/db/seeds/settings.rb +++ b/db/seeds/settings.rb @@ -183,6 +183,25 @@ Setting.create_or_update( state: 'relative', frontend: true ) +Setting.create_if_not_exists( + title: 'Locale', + name: 'locale_default', + area: 'System::Base', + description: 'Defines the system default language.', + options: { + form: [ + { + name: 'locale_default', + } + ], + }, + state: 'en-us', + preferences: { + controller: 'SettingsAreaItemDefaultLocale', + permission: ['admin.system'], + }, + frontend: true +) options = {} (10..99).each do |item| options[item] = item diff --git a/lib/calendar_subscriptions/tickets.rb b/lib/calendar_subscriptions/tickets.rb index 631538042..571c2c698 100644 --- a/lib/calendar_subscriptions/tickets.rb +++ b/lib/calendar_subscriptions/tickets.rb @@ -11,7 +11,7 @@ class CalendarSubscriptions::Tickets def all events_data = [] - return events_data if @preferences.empty? + return events_data if @preferences.blank? events_data += new_open events_data += pending @@ -24,7 +24,7 @@ class CalendarSubscriptions::Tickets alarm = false - return alarm if @preferences.empty? + return alarm if @preferences.blank? return alarm if !@preferences[:alarm] @preferences[:alarm] @@ -34,11 +34,11 @@ class CalendarSubscriptions::Tickets owner_ids = [] - return owner_ids if @preferences.empty? - return owner_ids if !@preferences[ method ] - return owner_ids if @preferences[ method ].empty? + return owner_ids if @preferences.blank? + return owner_ids if !@preferences[method] + return owner_ids if @preferences[method].blank? - preferences = @preferences[ method ] + preferences = @preferences[method] if preferences[:own] owner_ids = [ @user.id ] @@ -54,7 +54,7 @@ class CalendarSubscriptions::Tickets events_data = [] owner_ids = owner_ids(:new_open) - return events_data if owner_ids.empty? + return events_data if owner_ids.blank? condition = { 'ticket.owner_id' => { @@ -76,7 +76,7 @@ class CalendarSubscriptions::Tickets condition: condition, ) - user_locale = @user.preferences['locale'] || 'en' + user_locale = @user.preferences['locale'] || Setting.get('locale_default') || 'en-us' translated_ticket = Translation.translate(user_locale, 'ticket') events_data = [] @@ -101,7 +101,7 @@ class CalendarSubscriptions::Tickets events_data = [] owner_ids = owner_ids(:pending) - return events_data if owner_ids.empty? + return events_data if owner_ids.blank? condition = { 'ticket.owner_id' => { @@ -126,7 +126,7 @@ class CalendarSubscriptions::Tickets condition: condition, ) - user_locale = @user.preferences['locale'] || 'en' + user_locale = @user.preferences['locale'] || Setting.get('locale_default') || 'en-us' translated_ticket = Translation.translate(user_locale, 'ticket') customer = Translation.translate(user_locale, 'customer') @@ -165,7 +165,7 @@ class CalendarSubscriptions::Tickets events_data = [] owner_ids = owner_ids(:escalation) - return events_data if owner_ids.empty? + return events_data if owner_ids.blank? condition = { 'ticket.owner_id' => { @@ -183,7 +183,7 @@ class CalendarSubscriptions::Tickets condition: condition, ) - user_locale = @user.preferences['locale'] || 'en' + user_locale = @user.preferences['locale'] || Setting.get('locale_default') || 'en-us' translated_ticket_escalation = Translation.translate(user_locale, 'ticket escalation') customer = Translation.translate(user_locale, 'customer') diff --git a/lib/notification_factory.rb b/lib/notification_factory.rb index 26de217e3..477a9994e 100644 --- a/lib/notification_factory.rb +++ b/lib/notification_factory.rb @@ -31,7 +31,7 @@ returns template_subject = nil template_body = '' - locale = data[:locale] || 'en' + locale = data[:locale] || Setting.get('locale_default') || 'en-us' template = data[:template] format = data[:format] type = data[:type] diff --git a/lib/notification_factory/mailer.rb b/lib/notification_factory/mailer.rb index 68dec4cf8..b949f044e 100644 --- a/lib/notification_factory/mailer.rb +++ b/lib/notification_factory/mailer.rb @@ -264,7 +264,7 @@ returns end template = NotificationFactory.template_read( - locale: data[:locale] || 'en', + locale: data[:locale] || Setting.get('locale_default') || 'en-us', template: data[:template], format: 'html', type: 'mailer', diff --git a/lib/notification_factory/renderer.rb b/lib/notification_factory/renderer.rb index 680200f5e..5e700c876 100644 --- a/lib/notification_factory/renderer.rb +++ b/lib/notification_factory/renderer.rb @@ -25,7 +25,7 @@ examples how to use def initialize(objects, locale, template, escape = true) @objects = objects - @locale = locale || 'en-us' + @locale = locale || Setting.get('locale_default') || 'en-us' @template = NotificationFactory::Template.new(template, escape) @escape = escape end diff --git a/lib/notification_factory/slack.rb b/lib/notification_factory/slack.rb index da8dc3b6c..87221565a 100644 --- a/lib/notification_factory/slack.rb +++ b/lib/notification_factory/slack.rb @@ -27,7 +27,7 @@ returns end template = NotificationFactory.template_read( - locale: data[:locale] || 'en', + locale: data[:locale] || Setting.get('locale_default') || 'en-us', template: data[:template], format: 'md', type: 'slack', diff --git a/test/unit/notification_factory_mailer_template_test.rb b/test/unit/notification_factory_mailer_template_test.rb index 7889b6057..2dc38a9e8 100644 --- a/test/unit/notification_factory_mailer_template_test.rb +++ b/test/unit/notification_factory_mailer_template_test.rb @@ -201,6 +201,66 @@ class NotificationFactoryMailerTemplateTest < ActiveSupport::TestCase assert_no_match('longname', result[:body]) assert_match('Current User', result[:body]) + Setting.set('locale_default', 'de-de') + result = NotificationFactory::Mailer.template( + template: 'ticket_update', + objects: { + ticket: ticket, + article: article, + recipient: agent1, + current_user: agent_current_user, + changes: changes, + }, + ) + assert_match('Ticket aktualisiert', result[:subject]) + assert_match('Notification<b>xxx</b>', result[:body]) + assert_match('wurde von', result[:body]) + assert_match('test123', result[:body]) + assert_match('Benachrichtigungseinstellungen Verwalten', result[:body]) + assert_no_match('Your', result[:body]) + assert_no_match('longname', result[:body]) + assert_match('Current User', result[:body]) + + Setting.set('locale_default', 'not_existing') + result = NotificationFactory::Mailer.template( + template: 'ticket_update', + objects: { + ticket: ticket, + article: article, + recipient: agent1, + current_user: agent_current_user, + changes: changes, + }, + ) + assert_match('Updated Ticket', result[:subject]) + assert_match('Notification<b>xxx</b>', result[:body]) + assert_match('has been updated by', result[:body]) + assert_match('test123', result[:body]) + assert_match('Manage your notifications settings', result[:body]) + assert_no_match('Dein', result[:body]) + assert_no_match('longname', result[:body]) + assert_match('Current User', result[:body]) + + Setting.set('locale_default', 'pt-br') + result = NotificationFactory::Mailer.template( + template: 'ticket_update', + objects: { + ticket: ticket, + article: article, + recipient: agent1, + current_user: agent_current_user, + changes: changes, + }, + ) + assert_match('Chamado atualizado', result[:subject]) + assert_match('Notification<b>xxx</b>', result[:body]) + assert_match('foi atualizado por', result[:body]) + assert_match('test123', result[:body]) + assert_match('Manage your notifications settings', result[:body]) + assert_no_match('Dein', result[:body]) + assert_no_match('longname', result[:body]) + assert_match('Current User', result[:body]) + end end