Improved admin translation interface.

This commit is contained in:
Martin Edenhofer 2015-06-28 02:16:47 +02:00
parent 423c7428a7
commit 436ddad323
7 changed files with 227 additions and 39 deletions

View file

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

View file

@ -3,6 +3,9 @@
<h1><%- @T('Translations') %> <small></small></h1>
</div>
<div class="page-header-meta">
<a class="btn btn--success js-syncChanges"><%- @T('Sync with latest') %></a>
<a class="btn btn--danger hidden js-changes js-resetChanges"><%- @T('Reset Changes') %></a>
<a class="btn btn--primary hidden js-changes js-pushChanges"><%- @T('Push Changes') %></a>
<div class="language"></div>
</div>
</div>

View file

@ -13,7 +13,7 @@
<tr>
<td title="<%= item[1] %>"><%= item[1] %></td>
<td class="translationOverview-itemContainer"><input class="js-Item translationOverview-item form-control" value="<%= item[2] %>" data-source="<%= item[1] %>"></td>
<td><a href="#" class="js-Create"><%- @T('Create') %></a> / <a href="#" class="js-TheSame"><%- @T('is the same') %></a></td>
<td><a href="#" class="js-create"><%- @T('Create') %></a> / <a href="#" class="js-theSame"><%- @T('is the same') %></a></td>
</tr>
<% end %>
<% end %>

View file

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

View file

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

View file

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

View file

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