From 3e92e4f9f4bcb272d73ff135d347f35d3f80abcb Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 26 Jun 2017 15:16:03 +0200 Subject: [PATCH] Added locale rtl support (e. g. for Persian or Hebrew). --- .../javascripts/app/lib/app_post/i18n.coffee | 18 +++--- app/models/translation.rb | 62 ++++++++++++++++++- db/migrate/20120101000001_create_base.rb | 1 + db/migrate/20170619000001_tree_select.rb | 4 ++ .../20170626000001_locale_add_direction.rb | 9 +++ 5 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20170626000001_locale_add_direction.rb diff --git a/app/assets/javascripts/app/lib/app_post/i18n.coffee b/app/assets/javascripts/app/lib/app_post/i18n.coffee index 1b138bf4e..3dd198b70 100644 --- a/app/assets/javascripts/app/lib/app_post/i18n.coffee +++ b/app/assets/javascripts/app/lib/app_post/i18n.coffee @@ -96,12 +96,15 @@ class _i18nSingleton extends Spine.Module # prepare locale localeToSet = localeToSet.toLowerCase() + dirToSet = 'ltr' # check if locale exists localeFound = false locales = App.Locale.all() for locale in locales if locale.locale is localeToSet + localeToSet = locale.locale + dirToSet = locale.dir localeFound = true # try aliases @@ -109,6 +112,8 @@ class _i18nSingleton extends Spine.Module for locale in locales if locale.alias is localeToSet localeToSet = locale.locale + dirToSet = locale.dir + localeFound = true # if no locale and no alias was found, try to find correct one if !localeFound @@ -118,15 +123,9 @@ class _i18nSingleton extends Spine.Module for locale in locales if locale.alias is localeToSet localeToSet = locale.locale + dirToSet = locale.dir localeFound = true - # try to find by locale - if !localeFound - for locale in locales - if locale.locale is localeToSet - localeToSet = locale.locale - localeFound = true - # check if locale need to be changed return if localeToSet is @locale @@ -136,8 +135,9 @@ class _i18nSingleton extends Spine.Module # set if not translated should be logged @_notTranslatedLog = @notTranslatedFeatureEnabled(@locale) - # set lang attribute of html tag - $('html').prop('lang', @locale.substr(0, 2) ) + # set lang and dir attribute of html tag + $('html').prop('lang', localeToSet.substr(0, 2)) + $('html').prop('dir', dirToSet) @mapString = {} App.Ajax.request( diff --git a/app/models/translation.rb b/app/models/translation.rb index 81744f445..9f536b32d 100644 --- a/app/models/translation.rb +++ b/app/models/translation.rb @@ -1,4 +1,5 @@ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ +require 'csv' class Translation < ApplicationModel before_create :set_initial @@ -212,7 +213,7 @@ translate strings in ruby context, e. g. for notifications =begin -load locales from local +load translations from local all: @@ -282,6 +283,65 @@ all: true end +=begin + +load translations from csv file + +all: + + Translation.load_from_csv + + or + + Translation.load_from_csv(locale, file_location, file_charset) # e. g. 'en-us' or 'de-de' and /path/to/translation_list.csv + + e. g. + + Translation.load_from_csv('he-il', '/Users/me/Downloads/Hebrew_translation_list-1.csv', 'Windows-1255') + +Get source file at https://i18n.zammad.com/api/v1/translations_empty_translation_list + +=end + + def self.load_from_csv(locale_name, location, charset = 'UTF8') + locale = Locale.find_by(locale: locale_name) + if !locale + raise "No such locale: #{locale_name}" + end + + if !::File.exist?(location) + raise "No such file: #{location}" + end + + content = ::File.open(location, "r:#{charset}").read + params = { + col_sep: ',', + } + rows = ::CSV.parse(content, params) + header = rows.shift + + translation_raw = [] + rows.each { |row| + raise "Can't import translation, source is missing" if row[0].blank? + if row[1].blank? + warn "Skipped #{row[0]}, because translation is blank" + next + end + raise "Can't import translation, format is missing" if row[2].blank? + raise "Can't import translation, format is invalid (#{row[2]})" if row[2] !~ /^(time|string)$/ + item = { + 'locale' => locale.locale, + 'source' => row[0], + 'target' => row[1], + 'target_initial' => '', + 'format' => row[2], + } + translation_raw.push item + } + to_database(locale.name, translation_raw) + true + end + private_class_method def self.to_database(locale, data) translations = Translation.where(locale: locale).all ActiveRecord::Base.transaction do diff --git a/db/migrate/20120101000001_create_base.rb b/db/migrate/20120101000001_create_base.rb index bf8a7b719..6e4e773c1 100644 --- a/db/migrate/20120101000001_create_base.rb +++ b/db/migrate/20120101000001_create_base.rb @@ -209,6 +209,7 @@ class CreateBase < ActiveRecord::Migration t.string :locale, limit: 20, null: false t.string :alias, limit: 20, null: true t.string :name, limit: 255, null: false + t.string :dir, limit: 9, null: false, default: 'ltr' t.boolean :active, null: false, default: true t.timestamps limit: 3, null: false end diff --git a/db/migrate/20170619000001_tree_select.rb b/db/migrate/20170619000001_tree_select.rb index 6b75aa49d..69dddaad7 100644 --- a/db/migrate/20170619000001_tree_select.rb +++ b/db/migrate/20170619000001_tree_select.rb @@ -1,5 +1,9 @@ class TreeSelect < ActiveRecord::Migration def up + + # return if it's a new setup + return if !Setting.find_by(name: 'system_init_done') + change_column :object_manager_attributes, :data_option, :text, limit: 800.kilobytes + 1, null: true change_column :object_manager_attributes, :data_option_new, :text, limit: 800.kilobytes + 1, null: true end diff --git a/db/migrate/20170626000001_locale_add_direction.rb b/db/migrate/20170626000001_locale_add_direction.rb new file mode 100644 index 000000000..66fd8583c --- /dev/null +++ b/db/migrate/20170626000001_locale_add_direction.rb @@ -0,0 +1,9 @@ +class LocaleAddDirection < ActiveRecord::Migration + def up + + # return if it's a new setup + return if !Setting.find_by(name: 'system_init_done') + + add_column :locales, :dir, :string, limit: 9, null: false, default: 'ltr' + end +end