From dbc4d0ae5708c7acaed9a306dfe06045e1d5dcde Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 18 Nov 2015 14:27:46 +0100 Subject: [PATCH] Improved rerendering on translation changes. --- .../app/controllers/package.coffee | 25 +- .../app/controllers/session.coffee | 22 +- .../app/controllers/translation.coffee | 272 ++++++++---------- .../app/views/generic/navbar_l2.jst.eco | 17 -- .../views/generic/navbar_level2/index.jst.eco | 2 + .../generic/navbar_level2/navbar.jst.eco | 12 + .../app/views/generic/tabs.jst.eco | 10 +- .../javascripts/app/views/session.jst.eco | 2 +- .../app/views/translation/index.jst.eco | 3 +- .../app/views/translation/list.jst.eco | 36 ++- .../app/views/translation/todo.jst.eco | 13 +- app/controllers/translations_controller.rb | 6 +- app/models/translation.rb | 79 ++--- config/routes/translation.rb | 2 +- 14 files changed, 239 insertions(+), 262 deletions(-) delete mode 100644 app/assets/javascripts/app/views/generic/navbar_l2.jst.eco create mode 100644 app/assets/javascripts/app/views/generic/navbar_level2/index.jst.eco create mode 100644 app/assets/javascripts/app/views/generic/navbar_level2/navbar.jst.eco diff --git a/app/assets/javascripts/app/controllers/package.coffee b/app/assets/javascripts/app/controllers/package.coffee index 52abab74f..123621a7a 100644 --- a/app/assets/javascripts/app/controllers/package.coffee +++ b/app/assets/javascripts/app/controllers/package.coffee @@ -16,15 +16,16 @@ class Index extends App.ControllerContent @ajax( id: 'packages', type: 'GET', - url: @apiPath + '/packages', + url: "#{@apiPath}/packages", processData: true, success: (data) => - @render(data) + @packages = data + @render() ) - render: (data) -> + render: -> - for item in data.packages + for item in @packages item.action = [] if item.state == 'installed' # item.action = ['uninstall', 'deactivate'] @@ -36,7 +37,7 @@ class Index extends App.ControllerContent @html App.view('package')( head: 'Dashboard' - packages: data.packages + packages: @packages ) action: (e) -> @@ -48,13 +49,13 @@ class Index extends App.ControllerContent if httpType @ajax( - id: 'packages', - type: httpType, - url: @apiPath + '/packages', - data: JSON.stringify( { id: id } ), - processData: false, - success: (data) => + id: 'packages' + type: httpType + url: "#{@apiPath}/packages", + data: JSON.stringify( { id: id } ) + processData: false + success: => @load() ) -App.Config.set( 'Packages', { prio: 1000, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) \ No newline at end of file +App.Config.set( 'Packages', { prio: 1000, name: 'Packages', parent: '#system', target: '#system/package', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) diff --git a/app/assets/javascripts/app/controllers/session.coffee b/app/assets/javascripts/app/controllers/session.coffee index f149c081b..c69e5be51 100644 --- a/app/assets/javascripts/app/controllers/session.coffee +++ b/app/assets/javascripts/app/controllers/session.coffee @@ -1,7 +1,6 @@ class Index extends App.ControllerContent - divClass: 'lala' events: - 'click [data-type="delete"]': 'destroy' + 'click .js-delete': 'destroy' constructor: -> super @@ -27,26 +26,25 @@ class Index extends App.ControllerContent url: @apiPath + '/sessions' success: (data) => @stopLoading() - @render(data) + App.Collection.loadAssets(data.assets) + @sessions = data.sessions + @render() ) - render: (data) -> - - # load assets - App.Collection.loadAssets( data.assets ) + render: -> # fill users - for session in data.sessions + for session in @sessions if session.data && session.data.user_id - session.data.user = App.User.find( session.data.user_id ) + session.data.user = App.User.find(session.data.user_id) @html App.view('session')( - sessions: data.sessions + sessions: @sessions ) destroy: (e) -> e.preventDefault() - sessionId = $( e.target ).closest('a').data('session-id') + sessionId = $(e.target ).closest('a').data('session-id') @ajax( id: 'sessions/' + sessionId type: 'DELETE' @@ -55,4 +53,4 @@ class Index extends App.ControllerContent @load() ) -App.Config.set( 'Session', { prio: 3700, name: 'Sessions', parent: '#system', target: '#system/sessions', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) \ No newline at end of file +App.Config.set('Session', { prio: 3700, name: 'Sessions', parent: '#system', target: '#system/sessions', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/translation.coffee b/app/assets/javascripts/app/controllers/translation.coffee index 5362752f2..393971d0d 100644 --- a/app/assets/javascripts/app/controllers/translation.coffee +++ b/app/assets/javascripts/app/controllers/translation.coffee @@ -11,47 +11,87 @@ class Index extends App.ControllerContent return if !@authenticate() @title 'Translations', true - + @locale = App.i18n.get() @render() + @bind( + 'i18n:translation_update', + => + @load() + ) render: => - @html App.view('translation/index')() - options = {} locales = App.Locale.all() + currentLanguage = @locale for locale in locales - options[locale.locale] = locale.name - configure_attributes = [ - { name: 'locale', display: '', tag: 'select', null: false, class: 'input', options: options, default: App.i18n.get() }, - ] - load = (params) => - @translationToDo = new TranslationToDo( - el: @$('.js-ToDo') - locale: params.locale - ) - @translationList = new TranslationList( - el: @$('.js-List') - locale: params.locale - ) - - new App.ControllerForm( - el: @$('.language') - model: { configure_attributes: configure_attributes } - autofocus: false - handlers: [load] + if locale.locale is @locale + currentLanguage = locale.name + @html App.view('translation/index')( + currentLanguage: currentLanguage ) + @load() + + load: => + @ajax( + id: 'translations_admin' + type: 'GET' + url: "#{@apiPath}/translations/admin/lang/#{@locale}" + processData: true + success: (data, status, xhr) => + @times = [] + @stringsNotTranslated = [] + @stringsTranslated = [] + for item in data.list + + # if item has changed + if item[2] isnt item[3] + @showAction() + + # collect items + if item[4] is 'time' + @times.push item + else + if item[2] is '' + @stringsNotTranslated.push item + else + @stringsTranslated.push item + + if !@translationToDo + @translationToDo = new TranslationToDo( + el: @$('.js-ToDo') + locale: @locale + ) + @translationToDo.update( + stringsNotTranslated: @stringsNotTranslated + stringsTranslated: @stringsTranslated + times: @times + ) + if !@translationList + @translationList = new TranslationList( + el: @$('.js-List') + locale: @locale + ) + @translationList.update( + stringsNotTranslated: @stringsNotTranslated + stringsTranslated: @stringsTranslated + times: @times + ) + ) + + showAction: => + @$('.js-changes').removeClass('hidden') release: => rerender = -> App.Event.trigger('ui:rerender') - if @translationToDo.changes() || @translationList.changes() + console.log('rr') + if @translationList.changes() App.Delay.set(rerender, 400) + console.log('111', @translationList.changes()) hideAction: => @el.closest('.content').find('.js-changes').addClass('hidden') pushChanges: => - locale = @$('[name="locale"]').val() - @loader = new App.ControllerModalLoading( head: 'Push my changes' message: 'Pushing translations to i18n.zammad.com' @@ -62,7 +102,7 @@ class Index extends App.ControllerContent id: 'translations' type: 'PUT' url: "#{@apiPath}/translations/push" - data: JSON.stringify(locale: locale) + data: JSON.stringify(locale: @locale) processData: false success: (data, status, xhr) => @loader.update('Thanks for contributing!') @@ -73,8 +113,6 @@ class Index extends App.ControllerContent ) resetChanges: => - locale = @$('[name="locale"]').val() - @loader = new App.ControllerModalLoading( head: 'Reset changes' message: 'Reseting changes...' @@ -85,11 +123,10 @@ class Index extends App.ControllerContent id: 'translations' type: 'POST' url: "#{@apiPath}/translations/reset" - data: JSON.stringify(locale: locale) + 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') + App.Event.trigger('i18n:translation_update') @hideAction() @loader.hide() error: => @@ -97,8 +134,6 @@ class Index extends App.ControllerContent ) syncChanges: => - locale = @$('[name="locale"]').val() - @loader = new App.ControllerModalLoading( head: 'Get latest translations' message: 'Getting latest translations from i18n.zammad.com' @@ -106,8 +141,7 @@ class Index extends App.ControllerContent ) hide = => - App.Event.trigger('i18n:translation_todo_reload') - App.Event.trigger('i18n:translation_list_reload') + App.Event.trigger('i18n:translation_update') @hideAction() @loader.hide(1) @@ -131,19 +165,17 @@ class Index extends App.ControllerContent ) class TranslationToDo extends App.Controller - hasChanges: false events: 'click .js-create': 'create' 'click .js-theSame': 'same' constructor: -> super + + update: (data) => + for key, value of data + @[key] = value @render() - @bind( - 'i18n:translation_todo_reload', - => - @render() - ) render: => @@ -151,42 +183,37 @@ class TranslationToDo extends App.Controller @html App.view('translation/english')() return - if !App.i18n.getNotTranslated(@locale) + if !App.i18n.getNotTranslated(@locale) && _.isEmpty(@stringsNotTranslated) @html '' return - listNotTranslated = [] - for key, value of App.i18n.getNotTranslated(@locale) - item = [ '', key, '', ''] - listNotTranslated.push item + if App.i18n.getNotTranslated(@locale) + for key, value of App.i18n.getNotTranslated(@locale) + item = [ '', key, '', ''] + @stringsNotTranslated.push item @html App.view('translation/todo')( - list: listNotTranslated + list: @stringsNotTranslated ) - 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') + id = field.data('id') source = field.data('source') + format = 'string' target = field.val() + return if !target # remove from not translated list $(e.target).closest('tr').remove() # local update - App.i18n.removeNotTranslated( @locale, source ) + App.i18n.removeNotTranslated(@locale, source) # update runtime if same language is used if App.i18n.get() is @locale - App.i18n.setMap( source, target, 'string' ) + App.i18n.setMap(source, target, 'string') # remote update params = @@ -195,20 +222,27 @@ class TranslationToDo extends App.Controller target: target target_initial: '' + if id + method = 'PUT' + params.id = id + url = "#{@apiPath}/translations/#{id}" + else + method = 'POST' + url = "#{@apiPath}/translations" + @ajax( id: 'translations' - type: 'POST' - url: @apiPath + '/translations' + type: method + url: url data: JSON.stringify(params) processData: false success: (data, status, xhr) -> - App.Event.trigger('i18n:translation_list_reload') + App.Event.trigger('i18n:translation_update') ) same: (e) => e.preventDefault() @hasChanges = true - @showAction() field = $(e.target).closest('tr').find('.js-Item') source = field.data('source') @@ -216,11 +250,11 @@ class TranslationToDo extends App.Controller $(e.target).closest('tr').remove() # local update - App.i18n.removeNotTranslated( @locale, source ) + App.i18n.removeNotTranslated(@locale, source) # update runtime if same language is used if App.i18n.get() is @locale - App.i18n.setMap( source, source, 'string' ) + App.i18n.setMap(source, source, 'string') # remote update params = @@ -236,65 +270,33 @@ class TranslationToDo extends App.Controller data: JSON.stringify(params) processData: false success: (data, status, xhr) -> - App.Event.trigger('i18n:translation_list_reload') + App.Event.trigger('i18n:translation_update') ) class TranslationList extends App.Controller hasChanges: false events: - 'blur .js-translated input': 'update' - 'click .js-translated .js-Reset': 'reset' + 'blur .js-translated input': 'updateItem' + 'click .js-translated .js-Reset': 'resetItem' constructor: -> super - @load() - @bind( - 'i18n:translation_list_reload', - => - @load() - ) - load: => - @startLoading() - @ajax( - id: 'translations_admin' - type: 'GET' - url: @apiPath + "/translations/admin/lang/#{@locale}" - processData: true - success: (data, status, xhr) => - @stopLoading() - @render(data) - ) - - render: (data = {}) => - @strings = [] - @times = [] - for item in data.list - if item[4] is 'time' - @times.push item - else - @strings.push item + update: (data) => + for key, value of data + @[key] = value + @render() + render: => @html App.view('translation/list')( times: @times - strings: @strings + strings: @stringsTranslated ) - ui = @ - @changesAvailable = false - @$('.js-Item').each( (e) -> - id = $(@).data('id') - ui.updateRow(id) - ) - if @changesAvailable - @showAction() - - showAction: => - @el.closest('.content').find('.js-changes').removeClass('hidden') changes: => @hasChanges - reset: (e) -> + resetItem: (e) -> e.preventDefault() @hasChanges = true field = $(e.target).closest('tr').find('.js-Item') @@ -303,38 +305,12 @@ class TranslationList extends App.Controller initial = field.data('initial') format = field.data('format') - # if it's translated by user it self, delete it - if !initial || initial is '' - - # locale reset - $(e.target).closest('tr').remove() - - # update runtime if same language is used - if App.i18n.get() is @locale - App.i18n.setMap( source, '', format ) - - # remote reset - params = - id: id - @ajax( - id: 'translations' - type: 'DELETE' - url: @apiPath + '/translations/' + id - data: JSON.stringify(params) - processData: false - success: => - App.i18n.setNotTranslated( @locale, source ) - App.Event.trigger('i18n:translation_todo_reload') - ) - return - - # update runtime if same language is used if App.i18n.get() is @locale - App.i18n.setMap( source, initial, format ) + App.i18n.setMap(source, initial, format) # locale reset - field.val( initial ) + field.val(initial) @updateRow(id) # remote reset @@ -345,24 +321,29 @@ class TranslationList extends App.Controller @ajax( id: 'translations' type: 'PUT' - url: @apiPath + '/translations/' + id + url: "#{@apiPath}/translations/#{id}" data: JSON.stringify(params) processData: false + success: (data, status, xhr) -> + App.Event.trigger('i18n:translation_update') ) - update: (e) -> + updateItem: (e) -> e.preventDefault() - id = $( e.target ).data('id') - source = $( e.target ).data('source') - format = $( e.target ).data('format') - target = $( e.target ).val() + @hasChanges = true + field = $(e.target).closest('tr').find('.js-Item') + id = field.data('id') + source = field.data('source') + format = field.data('format') + target = field.val() + return if !target # local update @updateRow(id) # update runtime if same language is used if App.i18n.get() is @locale - App.i18n.setMap( source, target, format ) + App.i18n.setMap(source, target, format) # remote update params = @@ -372,9 +353,11 @@ class TranslationList extends App.Controller @ajax( id: 'translations' type: 'PUT' - url: @apiPath + '/translations/' + id + url: "#{@apiPath}/translations/#{id}" data: JSON.stringify(params) processData: false + success: (data, status, xhr) -> + App.Event.trigger('i18n:translation_update') ) updateRow: (id) => @@ -384,11 +367,10 @@ class TranslationList extends App.Controller reset = field.closest('tr').find('.js-Reset') if current isnt initial @changesAvailable = true - @showAction() - reset.show() + reset.removeClass('hidden') reset.closest('tr').addClass('warning') else - reset.hide() + reset.addClass('hidden') 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' ) diff --git a/app/assets/javascripts/app/views/generic/navbar_l2.jst.eco b/app/assets/javascripts/app/views/generic/navbar_l2.jst.eco deleted file mode 100644 index 81a10f246..000000000 --- a/app/assets/javascripts/app/views/generic/navbar_l2.jst.eco +++ /dev/null @@ -1,17 +0,0 @@ - -
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/navbar_level2/index.jst.eco b/app/assets/javascripts/app/views/generic/navbar_level2/index.jst.eco new file mode 100644 index 000000000..e5df2f0fe --- /dev/null +++ b/app/assets/javascripts/app/views/generic/navbar_level2/index.jst.eco @@ -0,0 +1,2 @@ + +
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/navbar_level2/navbar.jst.eco b/app/assets/javascripts/app/views/generic/navbar_level2/navbar.jst.eco new file mode 100644 index 000000000..17ab75490 --- /dev/null +++ b/app/assets/javascripts/app/views/generic/navbar_level2/navbar.jst.eco @@ -0,0 +1,12 @@ +<% if @groups: %> + <% for group in @groups: %> +

<%- @T(group.name) %>

+ + <% end %> +<% end %> diff --git a/app/assets/javascripts/app/views/generic/tabs.jst.eco b/app/assets/javascripts/app/views/generic/tabs.jst.eco index 4c2127886..43e7437e6 100644 --- a/app/assets/javascripts/app/views/generic/tabs.jst.eco +++ b/app/assets/javascripts/app/views/generic/tabs.jst.eco @@ -11,10 +11,12 @@ <% end %>
-
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/session.jst.eco b/app/assets/javascripts/app/views/session.jst.eco index 329769440..85e4151b4 100644 --- a/app/assets/javascripts/app/views/session.jst.eco +++ b/app/assets/javascripts/app/views/session.jst.eco @@ -21,7 +21,7 @@ <% if session.data.geo && session.data.geo.country_name: %><%= session.data.geo.country_name %> <%= session.data.geo.city_name %><% else: %><%= session.data.remote_id %><% end %> <%- @humanTime(session.created_at) %> <%- @humanTime(session.updated_at) %> - <%- @Icon('trash') %> + <%- @Icon('trash') %> <% end %> diff --git a/app/assets/javascripts/app/views/translation/index.jst.eco b/app/assets/javascripts/app/views/translation/index.jst.eco index ec2b63a9a..892e3b25e 100644 --- a/app/assets/javascripts/app/views/translation/index.jst.eco +++ b/app/assets/javascripts/app/views/translation/index.jst.eco @@ -1,12 +1,11 @@
diff --git a/app/assets/javascripts/app/views/translation/list.jst.eco b/app/assets/javascripts/app/views/translation/list.jst.eco index 407537d94..a0e669d4b 100644 --- a/app/assets/javascripts/app/views/translation/list.jst.eco +++ b/app/assets/javascripts/app/views/translation/list.jst.eco @@ -9,16 +9,15 @@ - <% if @times: %> - <% for time in @times: %> - - <%= time[1] %> - - <%= time[3]%> - <%- @T('Reset') %> - - <% end %> - <% end %> + <% for time in @times: %> + <% changed = false %> + <% changed = true if time[2] isnt time[3] %> + class="warning"<% end %>> + <%= time[1] %> + + <%= time[3]%> + <%- @T('Reset') %> + <% end %> @@ -33,15 +32,14 @@ - <% if @strings: %> - <% for item in @strings: %> - - <%= item[1] %> - - <%= item[3]%> - <%- @T('Reset') %> - - <% end %> + <% for item in @strings: %> + <% changed = false %> + <% changed = true if item[2] isnt item[3] %> + class="warning"<% end %>> + <%= item[1] %> + + <%= item[3]%> + <%- @T('Reset') %> <% end %> \ No newline at end of file diff --git a/app/assets/javascripts/app/views/translation/todo.jst.eco b/app/assets/javascripts/app/views/translation/todo.jst.eco index b273441aa..9c8b657bf 100644 --- a/app/assets/javascripts/app/views/translation/todo.jst.eco +++ b/app/assets/javascripts/app/views/translation/todo.jst.eco @@ -8,14 +8,11 @@ - <% if @list: %> - <% for item in @list: %> - - <%= item[1] %> - - <%- @T('Create') %> / <%- @T('is the same') %> - - <% end %> + <% for item in @list: %> + + <%= item[1] %> + + <%- @T('Create') %> / <%- @T('is the same') %> <% end %> \ No newline at end of file diff --git a/app/controllers/translations_controller.rb b/app/controllers/translations_controller.rb index 1cead7961..8a0fd03c4 100644 --- a/app/controllers/translations_controller.rb +++ b/app/controllers/translations_controller.rb @@ -4,8 +4,8 @@ class TranslationsController < ApplicationController before_action :authentication_check, except: [:load] # GET /translations/lang/:locale - def load - render json: Translation.list( params[:locale] ) + def lang + render json: Translation.lang(params[:locale]) end # PUT /translations/push @@ -36,7 +36,7 @@ class TranslationsController < ApplicationController # GET /translations/admin/lang/:locale def admin return if deny_if_not_role(Z_ROLENAME_ADMIN) - render json: Translation.list( params[:locale], true ) + render json: Translation.lang(params[:locale], true) end # GET /translations diff --git a/app/models/translation.rb b/app/models/translation.rb index dadee9ed4..5bb74d0bf 100644 --- a/app/models/translation.rb +++ b/app/models/translation.rb @@ -154,50 +154,53 @@ reset translations to origin get list of translations - list = Translation.list('de-de') + list = Translation.lang('de-de') =end - def self.list(locale, admin = false) + def self.lang(locale, admin = false) # use cache if not admin page is requested if !admin data = cache_get(locale) + return data if data end - if !data - # show total translations as reference count - data = { - 'total' => Translation.where(locale: 'de-de').count, - } - list = [] + # show total translations as reference count + data = { + 'total' => Translation.where(locale: 'de-de').count, + } + list = [] + if admin translations = Translation.where(locale: locale.downcase).order(:source) - translations.each { |item| - if admin - translation_item = [ - item.id, - item.source, - item.target, - item.target_initial, - item.format, - ] - list.push translation_item - else - translation_item = [ - item.id, - item.source, - item.target, - item.format, - ] - list.push translation_item - end - data['list'] = list - } - - # set cache - if !admin - cache_set(locale, data) + else + translations = Translation.where(locale: locale.downcase).where.not(target: '').order(:source) + end + translations.each { |item| + if admin + translation_item = [ + item.id, + item.source, + item.target, + item.target_initial, + item.format, + ] + list.push translation_item + else + translation_item = [ + item.id, + item.source, + item.target, + item.format, + ] + list.push translation_item end + data['list'] = list + } + + # set cache + if !admin + cache_set(locale, data) end data @@ -214,13 +217,13 @@ translate strings in ruby context, e. g. for notifications def self.translate(locale, string) # translate string - records = Translation.where( locale: locale, source: string ) + records = Translation.where(locale: locale, source: string) records.each {|record| return record.target if record.source == string } # fallback lookup in en - records = Translation.where( locale: 'en', source: string ) + records = Translation.where(locale: 'en', source: string) records.each {|record| return record.target if record.source == string } @@ -237,14 +240,14 @@ translate strings in ruby context, e. g. for notifications end def cache_clear - Cache.delete( 'TranslationMap::' + locale.downcase ) + Cache.delete('TranslationMapOnlyContent::' + locale.downcase) end def self.cache_set(locale, data) - Cache.write( 'TranslationMap::' + locale.downcase, data ) + Cache.write('TranslationMapOnlyContent::' + locale.downcase, data) end def self.cache_get(locale) - Cache.get( 'TranslationMap::' + locale.downcase ) + Cache.get('TranslationMapOnlyContent::' + locale.downcase) end end diff --git a/config/routes/translation.rb b/config/routes/translation.rb index 38eec40fe..bb9f38253 100644 --- a/config/routes/translation.rb +++ b/config/routes/translation.rb @@ -4,7 +4,7 @@ Zammad::Application.routes.draw do match api_path + '/translations/push', to: 'translations#push', via: :put match api_path + '/translations/sync/:locale', to: 'translations#sync', via: :get 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/lang/:locale', to: 'translations#lang', via: :get match api_path + '/translations/admin/lang/:locale', to: 'translations#admin', via: :get match api_path + '/translations', to: 'translations#index', via: :get