diff --git a/app/assets/javascripts/app/controllers/translation.js.coffee b/app/assets/javascripts/app/controllers/translation.js.coffee
index 98e08f95e..626abf5ad 100644
--- a/app/assets/javascripts/app/controllers/translation.js.coffee
+++ b/app/assets/javascripts/app/controllers/translation.js.coffee
@@ -1,4 +1,9 @@
class Index extends App.ControllerContent
+ events:
+ 'click .js-pushChanges': 'pushChanges'
+ 'click .js-resetChanges': 'resetChanges'
+ 'click .js-syncChanges': 'syncChanges'
+
constructor: ->
super
@@ -19,11 +24,11 @@ class Index extends App.ControllerContent
{ name: 'locale', display: '', tag: 'select', null: false, class: 'input', options: options, default: App.i18n.get() },
]
load = (params) =>
- new TranslationToDo(
+ @translationToDo = new TranslationToDo(
el: @$('.js-ToDo')
locale: params.locale
)
- new TranslationList(
+ @translationList = new TranslationList(
el: @$('.js-List')
locale: params.locale
)
@@ -38,12 +43,90 @@ class Index extends App.ControllerContent
release: =>
rerender = ->
App.Event.trigger('ui:rerender')
- App.Delay.set(rerender, 400)
+ if @translationToDo.changes() || @translationList.changes()
+ App.Delay.set(rerender, 400)
+
+ pushChanges: =>
+ locale = @$('[name="locale"]').val()
+
+ @modal = new App.ControllerModal(
+ head: 'Pushing own translations...'
+ message: 'Pushing own translations to i18n.zammad.com, Thanks for contributing!'
+ cancel: false
+ close: false
+ shown: true
+ container: @el.closest('.content')
+ )
+
+ @ajax(
+ id: 'translations'
+ type: 'PUT'
+ url: @apiPath + '/translations/push'
+ data: JSON.stringify(locale: locale)
+ processData: false
+ success: (data, status, xhr) =>
+ @modal.hide()
+ error: =>
+ @modal.hide()
+ )
+
+ resetChanges: =>
+ locale = @$('[name="locale"]').val()
+
+ @modal = new App.ControllerModal(
+ head: 'Reseting changes...'
+ message: 'Reseting changes own translation changes...'
+ cancel: false
+ close: false
+ shown: true
+ container: @el.closest('.content')
+ )
+
+ @ajax(
+ id: 'translations'
+ type: 'POST'
+ url: @apiPath + '/translations/reset'
+ data: JSON.stringify(locale: locale)
+ processData: false
+ success: (data, status, xhr) =>
+ App.Event.trigger('i18n:translation_todo_reload')
+ App.Event.trigger('i18n:translation_list_reload')
+ @modal.hide()
+ error: =>
+ @modal.hide()
+ )
+
+ syncChanges: =>
+ locale = @$('[name="locale"]').val()
+
+ @modal = new App.ControllerModal(
+ head: 'Syncing with latest translations...'
+ message: 'Syncing with latest translations!'
+ cancel: false
+ close: false
+ shown: true
+ container: @el.closest('.content')
+ )
+
+ @ajax(
+ id: 'translations'
+ type: 'POST'
+ url: @apiPath + '/translations/sync'
+ data: JSON.stringify(locale: locale)
+ processData: false
+ success: (data, status, xhr) =>
+ App.Event.trigger('i18n:translation_todo_reload')
+ App.Event.trigger('i18n:translation_list_reload')
+ @modal.hide()
+ error: =>
+ @modal.hide()
+ )
class TranslationToDo extends App.Controller
+ hasChanges: false
events:
- 'click .js-Create': 'create'
- 'click .js-TheSame': 'same'
+ 'click .js-create': 'create'
+ 'click .js-theSame': 'same'
constructor: ->
super
@@ -69,8 +152,16 @@ class TranslationToDo extends App.Controller
list: listNotTranslated
)
+ showAction: =>
+ @el.closest('.content').find('.js-changes').removeClass('hidden')
+
+ changes: =>
+ @hasChanges
+
create: (e) =>
e.preventDefault()
+ @hasChanges = true
+ @showAction()
field = $(e.target).closest('tr').find('.js-Item')
source = field.data('source')
target = field.val()
@@ -104,6 +195,8 @@ class TranslationToDo extends App.Controller
same: (e) =>
e.preventDefault()
+ @hasChanges = true
+ @showAction()
field = $(e.target).closest('tr').find('.js-Item')
source = field.data('source')
@@ -135,6 +228,7 @@ class TranslationToDo extends App.Controller
)
class TranslationList extends App.Controller
+ hasChanges: false
events:
'blur .js-translated input': 'update'
'click .js-translated .js-Reset': 'reset'
@@ -159,12 +253,8 @@ class TranslationList extends App.Controller
)
render: (data = {}) =>
-
- #if !App.i18n.notTranslatedFeatureEnabled(@locale)
- # return
-
@strings = []
- @times = []
+ @times = []
for item in data.list
if item[4] is 'time'
@times.push item
@@ -176,18 +266,29 @@ class TranslationList extends App.Controller
strings: @strings
)
ui = @
+ changesAvailable = false
@$('.js-Item').each( (e) ->
id = $(this).data('id')
ui.updateRow(id)
+ changesAvailable = true
)
+ if changesAvailable
+ @showAction()
+
+ showAction: =>
+ @el.closest('.content').find('.js-changes').removeClass('hidden')
+
+ changes: =>
+ @hasChanges
reset: (e) ->
e.preventDefault()
- field = $(e.target).closest('tr').find('.js-Item')
- id = field.data('id')
- source = field.data('source')
- initial = field.data('initial')
- format = field.data('format')
+ @hasChanges = true
+ field = $(e.target).closest('tr').find('.js-Item')
+ id = field.data('id')
+ source = field.data('source')
+ initial = field.data('initial')
+ format = field.data('format')
# if it's translated by user it self, delete it
if !initial || initial is ''
@@ -238,10 +339,11 @@ class TranslationList extends App.Controller
update: (e) ->
e.preventDefault()
- id = $( e.target ).data('id')
- source = $( e.target ).data('source')
- format = $( e.target ).data('format')
- target = $( e.target ).val()
+ @hasChanges = true
+ id = $( e.target ).data('id')
+ source = $( e.target ).data('source')
+ format = $( e.target ).data('format')
+ target = $( e.target ).val()
# local update
@updateRow(id)
diff --git a/app/assets/javascripts/app/views/translation/index.jst.eco b/app/assets/javascripts/app/views/translation/index.jst.eco
index f2b5a89dc..953e02f94 100644
--- a/app/assets/javascripts/app/views/translation/index.jst.eco
+++ b/app/assets/javascripts/app/views/translation/index.jst.eco
@@ -3,6 +3,9 @@
<%- @T('Translations') %>
diff --git a/app/assets/javascripts/app/views/translation/todo.jst.eco b/app/assets/javascripts/app/views/translation/todo.jst.eco
index 5885d63c8..b273441aa 100644
--- a/app/assets/javascripts/app/views/translation/todo.jst.eco
+++ b/app/assets/javascripts/app/views/translation/todo.jst.eco
@@ -13,7 +13,7 @@
<%= item[1] %> |
|
- <%- @T('Create') %> / <%- @T('is the same') %> |
+ <%- @T('Create') %> / <%- @T('is the same') %> |
<% end %>
<% end %>
diff --git a/app/controllers/translations_controller.rb b/app/controllers/translations_controller.rb
index cb6a27ed2..854e95aaa 100644
--- a/app/controllers/translations_controller.rb
+++ b/app/controllers/translations_controller.rb
@@ -8,6 +8,31 @@ class TranslationsController < ApplicationController
render json: Translation.list( params[:locale] )
end
+ # PUT /translations/push
+ def push
+ return if deny_if_not_role(Z_ROLENAME_ADMIN)
+ start = Time.zone.now
+ Translation.push(params[:locale])
+ if start > Time.zone.now - 5.seconds
+ sleep 4
+ end
+ render json: { message: 'ok' }, status: :ok
+ end
+
+ # POST /translations/sync
+ def sync
+ return if deny_if_not_role(Z_ROLENAME_ADMIN)
+ Translation.load
+ render json: { message: 'ok' }, status: :ok
+ end
+
+ # POST /translations/reset
+ def reset
+ return if deny_if_not_role(Z_ROLENAME_ADMIN)
+ Translation.reset(params[:locale])
+ render json: { message: 'ok' }, status: :ok
+ end
+
# GET /translations/admin/lang/:locale
def admin
return if deny_if_not_role(Z_ROLENAME_ADMIN)
@@ -16,11 +41,13 @@ class TranslationsController < ApplicationController
# GET /translations
def index
+ return if deny_if_not_role(Z_ROLENAME_ADMIN)
model_index_render(Translation, params)
end
# GET /translations/1
def show
+ return if deny_if_not_role(Z_ROLENAME_ADMIN)
model_show_render(Translation, params)
end
diff --git a/app/models/translation.rb b/app/models/translation.rb
index 501a9abed..dbd4dce86 100644
--- a/app/models/translation.rb
+++ b/app/models/translation.rb
@@ -72,22 +72,54 @@ push translations to online
}
return true if translations_to_push.empty?
- #return translations_to_push
+
url = 'https://i18n.zammad.com/api/v1/thanks_for_your_support'
+ translator_key = Setting.get('translator_key')
+
result = UserAgent.post(
url,
{
locale: locale,
translations: translations_to_push,
fqdn: Setting.get('fqdn'),
- translator_key: '',
+ translator_key: translator_key,
},
{
json: true,
}
)
fail "Can't push translations to #{url}: #{result.error}" if !result.success?
+
+ # set new translator_key if given
+ if result.data['translator_key']
+ translator_key = Setting.set('translator_key', result.data['translator_key'])
+ end
+
+ true
+ end
+
+=begin
+
+reset translations to origin
+
+ Translation.reset(locale)
+
+=end
+
+ def self.reset(locale)
+
+ # only push changed translations
+ translations = Translation.where(locale: locale)
+ translations.each {|translation|
+ if !translation.target_initial || translation.target_initial.empty?
+ translation.destroy
+ elsif translation.target != translation.target_initial
+ translation.target = translation.target_initial
+ translation.save
+ end
+ }
+
true
end
@@ -101,43 +133,47 @@ get list of translations
def self.list(locale, admin = false)
- # check cache
+ # use cache if not admin page is requested
if !admin
- list = cache_get( locale )
+ data = cache_get(locale)
end
- if !list
+ if !data
+
+ # show total translations as reference count
+ data = {
+ 'total' => Translation.where(locale: 'de-de').count,
+ }
list = []
- translations = Translation.where( locale: locale.downcase ).order( :source )
+ translations = Translation.where(locale: locale.downcase).order(:source)
translations.each { |item|
if admin
- data = [
+ translation_item = [
item.id,
item.source,
item.target,
item.target_initial,
item.format,
]
- list.push data
+ list.push translation_item
else
- data = [
+ translation_item = [
item.id,
item.source,
item.target,
item.format,
]
- list.push data
+ list.push translation_item
end
+ data['list'] = list
}
# set cache
if !admin
- cache_set( locale, list )
+ cache_set(locale, data)
end
end
- {
- list: list,
- }
+ data
end
=begin
@@ -174,12 +210,12 @@ translate strings in ruby context, e. g. for notifications
end
def cache_clear
- Cache.delete( 'Translation::' + locale.downcase )
+ Cache.delete( 'TranslationMap::' + locale.downcase )
end
def self.cache_set(locale, data)
- Cache.write( 'Translation::' + locale.downcase, data )
+ Cache.write( 'TranslationMap::' + locale.downcase, data )
end
def self.cache_get(locale)
- Cache.get( 'Translation::' + locale.downcase )
+ Cache.get( 'TranslationMap::' + locale.downcase )
end
end
diff --git a/config/routes/translation.rb b/config/routes/translation.rb
index 9293a85f9..c7281fbad 100644
--- a/config/routes/translation.rb
+++ b/config/routes/translation.rb
@@ -1,12 +1,16 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
+ match api_path + '/translations/push', to: 'translations#push', via: :put
+ match api_path + '/translations/sync', to: 'translations#sync', via: :post
+ match api_path + '/translations/reset', to: 'translations#reset', via: :post
+ match api_path + '/translations/lang/:locale', to: 'translations#load', via: :get
+ match api_path + '/translations/admin/lang/:locale', to: 'translations#admin', via: :get
+
match api_path + '/translations', to: 'translations#index', via: :get
match api_path + '/translations/:id', to: 'translations#show', via: :get
match api_path + '/translations', to: 'translations#create', via: :post
match api_path + '/translations/:id', to: 'translations#update', via: :put
match api_path + '/translations/:id', to: 'translations#destroy', via: :delete
- match api_path + '/translations/lang/:locale', to: 'translations#load', via: :get
- match api_path + '/translations/admin/lang/:locale', to: 'translations#admin', via: :get
end
diff --git a/db/migrate/20150628000001_translator_key_add.rb b/db/migrate/20150628000001_translator_key_add.rb
new file mode 100644
index 000000000..50e1457c9
--- /dev/null
+++ b/db/migrate/20150628000001_translator_key_add.rb
@@ -0,0 +1,16 @@
+class TranslatorKeyAdd < ActiveRecord::Migration
+ def up
+ Setting.create_if_not_exists(
+ title: 'Define translator identifier.',
+ name: 'translator_key',
+ area: 'i18n::translator_key',
+ description: 'Defines the translator identifier for contributions.',
+ options: {},
+ state: '',
+ frontend: false
+ )
+ end
+
+ def down
+ end
+end