diff --git a/app/assets/javascripts/app/controllers/translation.js.coffee b/app/assets/javascripts/app/controllers/translation.js.coffee index 237919a9a..9e2ee320f 100644 --- a/app/assets/javascripts/app/controllers/translation.js.coffee +++ b/app/assets/javascripts/app/controllers/translation.js.coffee @@ -1,8 +1,4 @@ class Index extends App.ControllerContent - events: - 'blur input': 'update' - 'click .js-Reset': 'reset' - constructor: -> super @@ -12,23 +8,144 @@ class Index extends App.ControllerContent @title 'Translations' @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() + @bind( + 'i18n:translation_list_reload', + => + @load() + ) load: => @ajax( id: 'translations_admin' type: 'GET' - url: @apiPath + '/translations/admin/lang/de' + url: @apiPath + "/translations/admin/lang/#{@locale}" processData: true success: (data, status, xhr) => @render(data) ) render: (data = {}) => - @html App.view('translation')( - list: data.list - timestampFormat: data.timestampFormat - dateFormat: data.dateFormat + @html App.view('translation/list')( + list: data.list + timestampFormat: data.timestampFormat + dateFormat: data.dateFormat ) ui = @ @$('.js-Item').each( (e) -> @@ -40,7 +157,31 @@ class Index extends App.ControllerContent e.preventDefault() field = $(e.target).closest('tr').find('.js-Item') id = field.data('id') + source = field.data('source') 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 ) @updateRow(id) params = @@ -58,8 +199,14 @@ class Index extends App.ControllerContent update: (e) -> e.preventDefault() id = $( e.target ).data('id') + source = $( e.target ).data('source') target = $( e.target ).val() @updateRow(id) + + # local update + App.i18n.setMap( source, target ) + + # remote update params = id: id target: target @@ -84,5 +231,4 @@ class Index extends App.ControllerContent reset.hide() 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' ) \ No newline at end of file diff --git a/app/assets/javascripts/app/lib/app_post/i18n.js.coffee b/app/assets/javascripts/app/lib/app_post/i18n.js.coffee index ddbc2d5ae..f1123cc09 100644 --- a/app/assets/javascripts/app/lib/app_post/i18n.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/i18n.js.coffee @@ -6,44 +6,65 @@ class App.i18n @translateContent: ( string, args... ) -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.translateContent( string, args ) @translatePlain: ( string, args... ) -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.translatePlain( string, args ) @translateInline: ( string, args... ) -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.translateInline( string, args ) @translateTimestamp: ( args, offset = 0 ) -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.timestamp( args, offset ) @translateDate: ( args, offset = 0 ) -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.date( args, offset ) @get: -> if _instance == undefined - _instance ?= new _i18nSingleton + _instance ?= new _i18nSingleton() _instance.get() @set: ( args ) -> if _instance == undefined - _instance ?= new _i18nSingleton( args ) + _instance ?= new _i18nSingleton() _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 @include App.LogInclude constructor: ( locale ) -> - @map = {} + @map = {} + @_notTranslated = {} @dateFormat = 'yyyy-mm-dd' @timestampFormat = 'yyyy-mm-dd HH:MM' @@ -165,6 +186,9 @@ class _i18nSingleton extends Spine.Module @_translated = false translated = string 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" # search %s @@ -176,6 +200,18 @@ class _i18nSingleton extends Spine.Module # return translated string 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 ) => @convert(time, offset, @dateFormat) diff --git a/app/assets/javascripts/app/views/translation/index.jst.eco b/app/assets/javascripts/app/views/translation/index.jst.eco new file mode 100644 index 000000000..581ee1d2d --- /dev/null +++ b/app/assets/javascripts/app/views/translation/index.jst.eco @@ -0,0 +1,10 @@ +
+
+

<%- @T('Translations') %>

+
+
+
+
+
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/translation.jst.eco b/app/assets/javascripts/app/views/translation/list.jst.eco similarity index 88% rename from app/assets/javascripts/app/views/translation.jst.eco rename to app/assets/javascripts/app/views/translation/list.jst.eco index a19a202f3..6c442d24a 100644 --- a/app/assets/javascripts/app/views/translation.jst.eco +++ b/app/assets/javascripts/app/views/translation/list.jst.eco @@ -1,6 +1,3 @@ -
-

<%- @T('Translations') %>

-

<%- @T('Date & Datetime') %>

@@ -28,7 +25,7 @@

<%- @T('Words') %>

- +
@@ -42,7 +39,7 @@ <% for item in @list: %> - + diff --git a/app/assets/javascripts/app/views/translation/todo.jst.eco b/app/assets/javascripts/app/views/translation/todo.jst.eco new file mode 100644 index 000000000..5885d63c8 --- /dev/null +++ b/app/assets/javascripts/app/views/translation/todo.jst.eco @@ -0,0 +1,21 @@ +

<%- @T('Words') %> <%- @T('not translated') %>

+
<%- @T('Source') %>
<%= item[1] %> <%= item[3]%> <%- @T('Reset') %>
+ + + + + + + + + <% if @list: %> + <% for item in @list: %> + + + + + + <% end %> + <% end %> + +
<%- @T('Source') %><%- @T('Target') %><%- @T('Action') %>
<%= item[1] %><%- @T('Create') %> / <%- @T('is the same') %>
\ No newline at end of file diff --git a/app/assets/stylesheets/zammad.css.scss b/app/assets/stylesheets/zammad.css.scss index fba803ca3..0dcfffde9 100644 --- a/app/assets/stylesheets/zammad.css.scss +++ b/app/assets/stylesheets/zammad.css.scss @@ -5282,9 +5282,6 @@ label + .wizard-buttonList { .translationOverview-initial { width: 25%; } - .translationOverview-action { - width: 15%; - } .translationOverview-item { width: 100%; }