Improved admin interface for translations.
This commit is contained in:
parent
c1d700c82e
commit
466bde7feb
6 changed files with 234 additions and 27 deletions
|
@ -1,8 +1,4 @@
|
||||||
class Index extends App.ControllerContent
|
class Index extends App.ControllerContent
|
||||||
events:
|
|
||||||
'blur input': 'update'
|
|
||||||
'click .js-Reset': 'reset'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
|
@ -12,23 +8,144 @@ class Index extends App.ControllerContent
|
||||||
@title 'Translations'
|
@title 'Translations'
|
||||||
|
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
@html App.view('translation/index')()
|
||||||
|
configure_attributes = [
|
||||||
|
{ name: 'locale', display: '', tag: 'select', null: false, class: 'input', options: { de: 'Deutsch', en: 'English (United States)', 'en-CA': 'English (Canada)', 'en-GB': 'English (United Kingdom)' }, default: App.i18n.get() },
|
||||||
|
]
|
||||||
|
load = (params) =>
|
||||||
|
new TranslationToDo(
|
||||||
|
el: @$('.js-ToDo')
|
||||||
|
locale: params.locale
|
||||||
|
)
|
||||||
|
new TranslationList(
|
||||||
|
el: @$('.js-List')
|
||||||
|
locale: params.locale
|
||||||
|
)
|
||||||
|
|
||||||
|
new App.ControllerForm(
|
||||||
|
el: @$('.language')
|
||||||
|
model: { configure_attributes: configure_attributes }
|
||||||
|
autofocus: false
|
||||||
|
handlers: [load]
|
||||||
|
)
|
||||||
|
|
||||||
|
release: =>
|
||||||
|
App.Event.trigger('ui:rerender')
|
||||||
|
|
||||||
|
class TranslationToDo extends App.Controller
|
||||||
|
events:
|
||||||
|
'click .js-Create': 'create'
|
||||||
|
'click .js-TheSame': 'same'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@render()
|
||||||
|
@bind(
|
||||||
|
'i18n:translation_todo_reload',
|
||||||
|
=>
|
||||||
|
@render()
|
||||||
|
)
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
listNotTranslated = []
|
||||||
|
for key, value of App.i18n.getNotTranslated(@locale)
|
||||||
|
item = [ '', key, '', '']
|
||||||
|
listNotTranslated.push item
|
||||||
|
|
||||||
|
@html App.view('translation/todo')(
|
||||||
|
list: listNotTranslated
|
||||||
|
)
|
||||||
|
|
||||||
|
create: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
field = $(e.target).closest('tr').find('.js-Item')
|
||||||
|
source = field.data('source')
|
||||||
|
target = field.val()
|
||||||
|
|
||||||
|
# remove from not translated list
|
||||||
|
$(e.target).closest('tr').remove()
|
||||||
|
|
||||||
|
# local update
|
||||||
|
App.i18n.removeNotTranslated( @locale, source )
|
||||||
|
App.i18n.setMap( source, target )
|
||||||
|
|
||||||
|
# remote update
|
||||||
|
params =
|
||||||
|
locale: @locale
|
||||||
|
source: source
|
||||||
|
target: target
|
||||||
|
target_initial: ''
|
||||||
|
|
||||||
|
@ajax(
|
||||||
|
id: 'translations'
|
||||||
|
type: 'POST'
|
||||||
|
url: @apiPath + '/translations'
|
||||||
|
data: JSON.stringify(params)
|
||||||
|
processData: false
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
App.Event.trigger('i18n:translation_list_reload')
|
||||||
|
)
|
||||||
|
|
||||||
|
same: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
field = $(e.target).closest('tr').find('.js-Item')
|
||||||
|
source = field.data('source')
|
||||||
|
|
||||||
|
# remove from not translated list
|
||||||
|
$(e.target).closest('tr').remove()
|
||||||
|
|
||||||
|
# local update
|
||||||
|
App.i18n.removeNotTranslated( @locale, source )
|
||||||
|
App.i18n.setMap( source, source )
|
||||||
|
|
||||||
|
# remote update
|
||||||
|
params =
|
||||||
|
locale: @locale
|
||||||
|
source: source
|
||||||
|
target: source
|
||||||
|
target_initial: ''
|
||||||
|
|
||||||
|
@ajax(
|
||||||
|
id: 'translations'
|
||||||
|
type: 'POST'
|
||||||
|
url: @apiPath + '/translations'
|
||||||
|
data: JSON.stringify(params)
|
||||||
|
processData: false
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
App.Event.trigger('i18n:translation_list_reload')
|
||||||
|
)
|
||||||
|
|
||||||
|
class TranslationList extends App.Controller
|
||||||
|
events:
|
||||||
|
'blur .js-translated input': 'update'
|
||||||
|
'click .js-translated .js-Reset': 'reset'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
@load()
|
@load()
|
||||||
|
@bind(
|
||||||
|
'i18n:translation_list_reload',
|
||||||
|
=>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
|
|
||||||
load: =>
|
load: =>
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'translations_admin'
|
id: 'translations_admin'
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: @apiPath + '/translations/admin/lang/de'
|
url: @apiPath + "/translations/admin/lang/#{@locale}"
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@render(data)
|
@render(data)
|
||||||
)
|
)
|
||||||
|
|
||||||
render: (data = {}) =>
|
render: (data = {}) =>
|
||||||
@html App.view('translation')(
|
@html App.view('translation/list')(
|
||||||
list: data.list
|
list: data.list
|
||||||
timestampFormat: data.timestampFormat
|
timestampFormat: data.timestampFormat
|
||||||
dateFormat: data.dateFormat
|
dateFormat: data.dateFormat
|
||||||
)
|
)
|
||||||
ui = @
|
ui = @
|
||||||
@$('.js-Item').each( (e) ->
|
@$('.js-Item').each( (e) ->
|
||||||
|
@ -40,7 +157,31 @@ class Index extends App.ControllerContent
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
field = $(e.target).closest('tr').find('.js-Item')
|
field = $(e.target).closest('tr').find('.js-Item')
|
||||||
id = field.data('id')
|
id = field.data('id')
|
||||||
|
source = field.data('source')
|
||||||
initial = field.data('initial')
|
initial = field.data('initial')
|
||||||
|
|
||||||
|
# if it's translated by user it self, delete it
|
||||||
|
if !initial || initial is ''
|
||||||
|
$(e.target).closest('tr').remove()
|
||||||
|
App.i18n.setMap( source, '' )
|
||||||
|
params =
|
||||||
|
id: id
|
||||||
|
@ajax(
|
||||||
|
id: 'translations'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: @apiPath + '/translations/' + id
|
||||||
|
data: JSON.stringify(params)
|
||||||
|
processData: false
|
||||||
|
success: =>
|
||||||
|
console.log('aaa', @locale, source)
|
||||||
|
App.i18n.setNotTranslated( @locale, source )
|
||||||
|
App.Event.trigger('i18n:translation_todo_reload')
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# update item
|
||||||
|
App.i18n.setMap( source, initial )
|
||||||
|
|
||||||
field.val( initial )
|
field.val( initial )
|
||||||
@updateRow(id)
|
@updateRow(id)
|
||||||
params =
|
params =
|
||||||
|
@ -58,8 +199,14 @@ class Index extends App.ControllerContent
|
||||||
update: (e) ->
|
update: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $( e.target ).data('id')
|
id = $( e.target ).data('id')
|
||||||
|
source = $( e.target ).data('source')
|
||||||
target = $( e.target ).val()
|
target = $( e.target ).val()
|
||||||
@updateRow(id)
|
@updateRow(id)
|
||||||
|
|
||||||
|
# local update
|
||||||
|
App.i18n.setMap( source, target )
|
||||||
|
|
||||||
|
# remote update
|
||||||
params =
|
params =
|
||||||
id: id
|
id: id
|
||||||
target: target
|
target: target
|
||||||
|
@ -84,5 +231,4 @@ class Index extends App.ControllerContent
|
||||||
reset.hide()
|
reset.hide()
|
||||||
reset.closest('tr').removeClass('warning')
|
reset.closest('tr').removeClass('warning')
|
||||||
|
|
||||||
|
App.Config.set( 'Translation', { prio: 1800, parent: '#system', name: 'Translations', target: '#system/translation', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
||||||
App.Config.set( 'Translation', { prio: 1800, parent: '#system', name: 'Translations', target: '#system/translation', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
|
|
@ -6,44 +6,65 @@ class App.i18n
|
||||||
|
|
||||||
@translateContent: ( string, args... ) ->
|
@translateContent: ( string, args... ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.translateContent( string, args )
|
_instance.translateContent( string, args )
|
||||||
|
|
||||||
@translatePlain: ( string, args... ) ->
|
@translatePlain: ( string, args... ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.translatePlain( string, args )
|
_instance.translatePlain( string, args )
|
||||||
|
|
||||||
@translateInline: ( string, args... ) ->
|
@translateInline: ( string, args... ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.translateInline( string, args )
|
_instance.translateInline( string, args )
|
||||||
|
|
||||||
@translateTimestamp: ( args, offset = 0 ) ->
|
@translateTimestamp: ( args, offset = 0 ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.timestamp( args, offset )
|
_instance.timestamp( args, offset )
|
||||||
|
|
||||||
@translateDate: ( args, offset = 0 ) ->
|
@translateDate: ( args, offset = 0 ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.date( args, offset )
|
_instance.date( args, offset )
|
||||||
|
|
||||||
@get: ->
|
@get: ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.get()
|
_instance.get()
|
||||||
|
|
||||||
@set: ( args ) ->
|
@set: ( args ) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _i18nSingleton( args )
|
_instance ?= new _i18nSingleton()
|
||||||
_instance.set( args )
|
_instance.set( args )
|
||||||
|
|
||||||
|
@setMap: (source, target) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _i18nSingleton()
|
||||||
|
_instance.setMap( source, target )
|
||||||
|
|
||||||
|
@getNotTranslated: (locale) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _i18nSingleton()
|
||||||
|
_instance.getNotTranslated( locale )
|
||||||
|
|
||||||
|
@removeNotTranslated: (locale, key) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _i18nSingleton()
|
||||||
|
_instance.removeNotTranslated( locale, key )
|
||||||
|
|
||||||
|
@setNotTranslated: (locale, key) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _i18nSingleton()
|
||||||
|
_instance.setNotTranslated( locale, key )
|
||||||
|
|
||||||
class _i18nSingleton extends Spine.Module
|
class _i18nSingleton extends Spine.Module
|
||||||
@include App.LogInclude
|
@include App.LogInclude
|
||||||
|
|
||||||
constructor: ( locale ) ->
|
constructor: ( locale ) ->
|
||||||
@map = {}
|
@map = {}
|
||||||
|
@_notTranslated = {}
|
||||||
@dateFormat = 'yyyy-mm-dd'
|
@dateFormat = 'yyyy-mm-dd'
|
||||||
@timestampFormat = 'yyyy-mm-dd HH:MM'
|
@timestampFormat = 'yyyy-mm-dd HH:MM'
|
||||||
|
|
||||||
|
@ -165,6 +186,9 @@ class _i18nSingleton extends Spine.Module
|
||||||
@_translated = false
|
@_translated = false
|
||||||
translated = string
|
translated = string
|
||||||
if App.Config.get('developer_mode') is true
|
if App.Config.get('developer_mode') is true
|
||||||
|
if !@_notTranslated[@locale]
|
||||||
|
@_notTranslated[@locale] = {}
|
||||||
|
@_notTranslated[@locale][string] = true
|
||||||
@log 'notice', "translation for '#{string}' in '#{@locale}' is missing"
|
@log 'notice', "translation for '#{string}' in '#{@locale}' is missing"
|
||||||
|
|
||||||
# search %s
|
# search %s
|
||||||
|
@ -176,6 +200,18 @@ class _i18nSingleton extends Spine.Module
|
||||||
# return translated string
|
# return translated string
|
||||||
return translated
|
return translated
|
||||||
|
|
||||||
|
setMap: ( source, target ) =>
|
||||||
|
@map[source] = target
|
||||||
|
|
||||||
|
getNotTranslated: ( locale ) =>
|
||||||
|
@_notTranslated[locale || @locale]
|
||||||
|
|
||||||
|
removeNotTranslated: ( locale, key ) =>
|
||||||
|
delete @_notTranslated[locale][key]
|
||||||
|
|
||||||
|
setNotTranslated: ( locale, key ) =>
|
||||||
|
@_notTranslated[locale][key] = true
|
||||||
|
|
||||||
date: ( time, offset ) =>
|
date: ( time, offset ) =>
|
||||||
@convert(time, offset, @dateFormat)
|
@convert(time, offset, @dateFormat)
|
||||||
|
|
||||||
|
|
10
app/assets/javascripts/app/views/translation/index.jst.eco
Normal file
10
app/assets/javascripts/app/views/translation/index.jst.eco
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="horizontal">
|
||||||
|
<div class="page-header-title">
|
||||||
|
<h1><%- @T('Translations') %> <small></small></h1>
|
||||||
|
</div>
|
||||||
|
<div class="page-header-meta">
|
||||||
|
<div class="language"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="js-ToDo"></div>
|
||||||
|
<div class="js-List"></div>
|
|
@ -1,6 +1,3 @@
|
||||||
<div class="page-header-title">
|
|
||||||
<h1><%- @T('Translations') %><small></small></h1>
|
|
||||||
</div>
|
|
||||||
<h2><%- @T('Date & Datetime') %></h2>
|
<h2><%- @T('Date & Datetime') %></h2>
|
||||||
<table class="translationOverview table table-striped table-hover">
|
<table class="translationOverview table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -28,7 +25,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2><%- @T('Words') %></h2>
|
<h2><%- @T('Words') %></h2>
|
||||||
<table class="translationOverview table table-striped table-hover">
|
<table class="translationOverview js-translated table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="translationOverview-source"><%- @T('Source') %></th>
|
<th class="translationOverview-source"><%- @T('Source') %></th>
|
||||||
|
@ -42,7 +39,7 @@
|
||||||
<% for item in @list: %>
|
<% for item in @list: %>
|
||||||
<tr>
|
<tr>
|
||||||
<td title="<%= item[1] %>"><%= item[1] %></td>
|
<td title="<%= item[1] %>"><%= item[1] %></td>
|
||||||
<td class="translationOverview-itemContainer"><input class="js-Item translationOverview-item form-control" value="<%= item[2] %>" data-initial="<%= item[3] %>" data-id="<%= item[0] %>"></td>
|
<td class="translationOverview-itemContainer"><input class="js-Item translationOverview-item form-control" value="<%= item[2] %>" data-source="<%= item[1] %>" data-initial="<%= item[3] %>" data-id="<%= item[0] %>"></td>
|
||||||
<td title="<%= item[3] %>"><%= item[3]%></td>
|
<td title="<%= item[3] %>"><%= item[3]%></td>
|
||||||
<td><a href="#" class="js-Reset"><%- @T('Reset') %></a></td>
|
<td><a href="#" class="js-Reset"><%- @T('Reset') %></a></td>
|
||||||
</tr>
|
</tr>
|
21
app/assets/javascripts/app/views/translation/todo.jst.eco
Normal file
21
app/assets/javascripts/app/views/translation/todo.jst.eco
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<h2><%- @T('Words') %> <small><%- @T('not translated') %></small></h2>
|
||||||
|
<table class="translationOverview table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="translationOverview-source"><%- @T('Source') %></th>
|
||||||
|
<th class="translationOverview-target"><%- @T('Target') %></th>
|
||||||
|
<th class="translationOverview-action"><%- @T('Action') %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% if @list: %>
|
||||||
|
<% for item in @list: %>
|
||||||
|
<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>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -5282,9 +5282,6 @@ label + .wizard-buttonList {
|
||||||
.translationOverview-initial {
|
.translationOverview-initial {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
.translationOverview-action {
|
|
||||||
width: 15%;
|
|
||||||
}
|
|
||||||
.translationOverview-item {
|
.translationOverview-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue