ad_localize 5.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +6 -3
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +319 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +54 -48
- data/README.md +32 -10
- data/Rakefile +1 -0
- data/ad_localize.gemspec +10 -9
- data/bin/console +1 -0
- data/exe/ad_localize +2 -1
- data/lib/ad_localize/ad_logger.rb +5 -10
- data/lib/ad_localize/cli.rb +10 -3
- data/lib/ad_localize/entities/key.rb +3 -76
- data/lib/ad_localize/entities/locale_wording.rb +32 -52
- data/lib/ad_localize/entities/platform.rb +13 -0
- data/lib/ad_localize/entities/simple_wording.rb +6 -0
- data/lib/ad_localize/entities/wording_type.rb +11 -0
- data/lib/ad_localize/interactors/base_generate_files.rb +37 -0
- data/lib/ad_localize/interactors/download_spreadsheets.rb +20 -0
- data/lib/ad_localize/interactors/export_wording.rb +26 -20
- data/lib/ad_localize/interactors/generate_info_plist.rb +24 -0
- data/lib/ad_localize/interactors/generate_ios_files.rb +12 -0
- data/lib/ad_localize/interactors/generate_json.rb +20 -0
- data/lib/ad_localize/interactors/generate_localizable_strings.rb +24 -0
- data/lib/ad_localize/interactors/generate_localizable_strings_dict.rb +24 -0
- data/lib/ad_localize/interactors/generate_properties.rb +20 -0
- data/lib/ad_localize/interactors/generate_strings.rb +25 -0
- data/lib/ad_localize/interactors/generate_yaml.rb +20 -0
- data/lib/ad_localize/interactors/merge_wordings.rb +49 -18
- data/lib/ad_localize/interactors/parse_csv_files.rb +22 -0
- data/lib/ad_localize/interactors/process_export_request.rb +21 -0
- data/lib/ad_localize/mappers/locale_wording_to_hash.rb +45 -24
- data/lib/ad_localize/mappers/options_to_export_request.rb +14 -22
- data/lib/ad_localize/option_handler.rb +50 -27
- data/lib/ad_localize/parsers/csv_parser.rb +84 -0
- data/lib/ad_localize/parsers/key_parser.rb +62 -0
- data/lib/ad_localize/repositories/drive_repository.rb +53 -0
- data/lib/ad_localize/repositories/file_system_repository.rb +2 -1
- data/lib/ad_localize/requests/export_request.rb +95 -57
- data/lib/ad_localize/sanitizers/ios_sanitizer.rb +12 -0
- data/lib/ad_localize/{mappers/android_translation_mapper.rb → sanitizers/ios_to_android_sanitizer.rb} +8 -8
- data/lib/ad_localize/sanitizers/pass_through_sanitizer.rb +10 -0
- data/lib/ad_localize/serializers/info_plist_serializer.rb +9 -11
- data/lib/ad_localize/serializers/json_serializer.rb +3 -5
- data/lib/ad_localize/serializers/localizable_strings_serializer.rb +9 -15
- data/lib/ad_localize/serializers/localizable_stringsdict_serializer.rb +12 -25
- data/lib/ad_localize/serializers/properties_serializer.rb +9 -11
- data/lib/ad_localize/serializers/strings_serializer.rb +12 -21
- data/lib/ad_localize/serializers/templated_serializer.rb +51 -0
- data/lib/ad_localize/serializers/yaml_serializer.rb +4 -6
- data/lib/ad_localize/templates/android/strings.xml.erb +6 -6
- data/lib/ad_localize/templates/ios/Localizable.stringsdict.erb +14 -14
- data/lib/ad_localize/version.rb +2 -1
- data/lib/ad_localize/view_models/compound_wording_view_model.rb +2 -0
- data/lib/ad_localize/view_models/simple_wording_view_model.rb +2 -0
- data/lib/ad_localize.rb +33 -35
- metadata +70 -47
- data/lib/ad_localize/constant.rb +0 -6
- data/lib/ad_localize/entities/translation.rb +0 -32
- data/lib/ad_localize/entities/wording.rb +0 -24
- data/lib/ad_localize/interactors/execute_export_request.rb +0 -45
- data/lib/ad_localize/interactors/export_csv_files.rb +0 -20
- data/lib/ad_localize/interactors/export_g_spreadsheet.rb +0 -64
- data/lib/ad_localize/interactors/platforms/export_android_locale_wording.rb +0 -44
- data/lib/ad_localize/interactors/platforms/export_csv_locale_wording.rb +0 -22
- data/lib/ad_localize/interactors/platforms/export_ios_locale_wording.rb +0 -75
- data/lib/ad_localize/interactors/platforms/export_json_locale_wording.rb +0 -27
- data/lib/ad_localize/interactors/platforms/export_platform_factory.rb +0 -50
- data/lib/ad_localize/interactors/platforms/export_properties_locale_wording.rb +0 -32
- data/lib/ad_localize/interactors/platforms/export_yaml_locale_wording.rb +0 -27
- data/lib/ad_localize/mappers/csv_path_to_wording.rb +0 -73
- data/lib/ad_localize/mappers/ios_translation_mapper.rb +0 -12
- data/lib/ad_localize/mappers/translation_group_mapper.rb +0 -14
- data/lib/ad_localize/mappers/translation_mapper.rb +0 -30
- data/lib/ad_localize/mappers/value_range_to_wording.rb +0 -67
- data/lib/ad_localize/repositories/g_sheets_repository.rb +0 -44
- data/lib/ad_localize/requests/export_wording_options.rb +0 -24
- data/lib/ad_localize/requests/g_spreadsheet_options.rb +0 -47
- data/lib/ad_localize/requests/merge_policy.rb +0 -28
- data/lib/ad_localize/serializers/with_template.rb +0 -19
- data/lib/ad_localize/validators/key_validator.rb +0 -31
- data/lib/ad_localize/view_models/translation_group_view_model.rb +0 -19
- data/lib/ad_localize/view_models/translation_view_model.rb +0 -23
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Interactors
|
|
3
|
-
module Platforms
|
|
4
|
-
class ExportIOSLocaleWording
|
|
5
|
-
INFO_PLIST_FILENAME = "InfoPlist.strings".freeze
|
|
6
|
-
LOCALIZABLE_STRINGS_FILENAME = "Localizable.strings".freeze
|
|
7
|
-
LOCALIZABLE_STRINGSDICT_FILENAME = "Localizable.stringsdict".freeze
|
|
8
|
-
LOCALE_DIRECTORY_CONVENTION = "%{locale}.lproj".freeze
|
|
9
|
-
|
|
10
|
-
def initialize
|
|
11
|
-
@info_plist_serializer = Serializers::InfoPlistSerializer.new
|
|
12
|
-
@strings_serializer = Serializers::LocalizableStringsSerializer.new
|
|
13
|
-
@stringsdict_serializer = Serializers::LocalizableStringsdictSerializer.new
|
|
14
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def call(export_wording_options:)
|
|
18
|
-
bypass_empty_values = export_wording_options.bypass_empty_values
|
|
19
|
-
|
|
20
|
-
export_wording_options.locales.each do |locale|
|
|
21
|
-
LOGGER.debug("Starting export iOS wording for locale #{locale}")
|
|
22
|
-
locale_wording = export_wording_options.wording.translations_for(locale: locale)
|
|
23
|
-
next unless has_ios_wording?(locale_wording: locale_wording)
|
|
24
|
-
|
|
25
|
-
locale_directory_name = LOCALE_DIRECTORY_CONVENTION % { locale: locale }
|
|
26
|
-
output_dir = export_wording_options.platform_output_directory.join(locale_directory_name)
|
|
27
|
-
@file_system_repository.create_directory(path: output_dir)
|
|
28
|
-
export_files(locale_wording: locale_wording, output_dir: output_dir, bypass_empty_values: bypass_empty_values)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def export_files(locale_wording:, output_dir:, bypass_empty_values:)
|
|
35
|
-
export_info_plist(locale_wording: locale_wording, output_dir: output_dir)
|
|
36
|
-
export_localizable_strings(locale_wording: locale_wording, output_dir: output_dir, bypass_empty_values: bypass_empty_values)
|
|
37
|
-
export_localizable_stringsdict(locale_wording: locale_wording, output_dir: output_dir, bypass_empty_values: bypass_empty_values)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def has_ios_wording?(locale_wording:)
|
|
41
|
-
locale_wording.has_info_plist_keys? ||
|
|
42
|
-
locale_wording.has_singular_keys? ||
|
|
43
|
-
locale_wording.has_plural_keys? ||
|
|
44
|
-
locale_wording.has_adaptive_keys?
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def export_info_plist(locale_wording:, output_dir:)
|
|
48
|
-
return unless locale_wording.has_info_plist_keys?
|
|
49
|
-
|
|
50
|
-
content = @info_plist_serializer.render(locale_wording: locale_wording)
|
|
51
|
-
@file_system_repository.write(content: content, path: output_dir.join(INFO_PLIST_FILENAME))
|
|
52
|
-
LOGGER.debug("#{INFO_PLIST_FILENAME} done !")
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def export_localizable_strings(locale_wording:, output_dir:, bypass_empty_values:)
|
|
56
|
-
return unless locale_wording.has_singular_keys?
|
|
57
|
-
|
|
58
|
-
@strings_serializer.bypass_empty_values = bypass_empty_values
|
|
59
|
-
content = @strings_serializer.render(locale_wording: locale_wording)
|
|
60
|
-
@file_system_repository.write(content: content, path: output_dir.join(LOCALIZABLE_STRINGS_FILENAME))
|
|
61
|
-
LOGGER.debug("#{LOCALIZABLE_STRINGS_FILENAME} done !")
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def export_localizable_stringsdict(locale_wording:, output_dir:, bypass_empty_values:)
|
|
65
|
-
return unless locale_wording.has_plural_keys? || locale_wording.has_adaptive_keys?
|
|
66
|
-
|
|
67
|
-
@stringsdict_serializer.bypass_empty_values = bypass_empty_values
|
|
68
|
-
content = @stringsdict_serializer.render(locale_wording: locale_wording)
|
|
69
|
-
@file_system_repository.write(content: content, path: output_dir.join(LOCALIZABLE_STRINGSDICT_FILENAME))
|
|
70
|
-
LOGGER.debug("#{LOCALIZABLE_STRINGSDICT_FILENAME} done !")
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Interactors
|
|
3
|
-
module Platforms
|
|
4
|
-
class ExportJSONLocaleWording
|
|
5
|
-
def initialize
|
|
6
|
-
@json_serializer = Serializers::JSONSerializer.new
|
|
7
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def call(export_wording_options:)
|
|
11
|
-
output_dir = export_wording_options.platform_output_directory
|
|
12
|
-
|
|
13
|
-
export_wording_options.locales.each do |locale|
|
|
14
|
-
LOGGER.debug("Starting export JSON wording for locale #{locale}")
|
|
15
|
-
locale_wording = export_wording_options.wording.translations_for(locale: locale)
|
|
16
|
-
content = @json_serializer.render(locale_wording: locale_wording)
|
|
17
|
-
next if content[locale].blank?
|
|
18
|
-
|
|
19
|
-
@file_system_repository.create_directory(path: output_dir)
|
|
20
|
-
@file_system_repository.write(content: content, path: output_dir.join("#{locale}.json"))
|
|
21
|
-
LOGGER.debug("#{locale}.json done !")
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Interactors
|
|
3
|
-
module Platforms
|
|
4
|
-
class ExportPlatformFactory
|
|
5
|
-
def build(platform:)
|
|
6
|
-
case platform
|
|
7
|
-
when 'json'
|
|
8
|
-
json_builder
|
|
9
|
-
when 'yml'
|
|
10
|
-
yaml_builder
|
|
11
|
-
when 'android'
|
|
12
|
-
android_builder
|
|
13
|
-
when 'ios'
|
|
14
|
-
ios_builder
|
|
15
|
-
when 'properties'
|
|
16
|
-
properties_builder
|
|
17
|
-
when 'csv'
|
|
18
|
-
csv_builder
|
|
19
|
-
else
|
|
20
|
-
raise ArgumentError.new('Unknown platform for builder factory')
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def json_builder
|
|
25
|
-
@json_builder ||= ExportJSONLocaleWording.new
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def yaml_builder
|
|
29
|
-
@yaml_builder ||= ExportYAMLLocaleWording.new
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def android_builder
|
|
33
|
-
@android_builder ||= ExportAndroidLocaleWording.new
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def ios_builder
|
|
37
|
-
@ios_builder ||= ExportIOSLocaleWording.new
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def properties_builder
|
|
41
|
-
@properties_builder ||= ExportPropertiesLocaleWording.new
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def csv_builder
|
|
45
|
-
@csv_builder ||= ExportCSVLocaleWording.new
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Interactors
|
|
3
|
-
module Platforms
|
|
4
|
-
class ExportPropertiesLocaleWording
|
|
5
|
-
def initialize
|
|
6
|
-
@properties_serializer = Serializers::PropertiesSerializer.new
|
|
7
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def call(export_wording_options:)
|
|
11
|
-
export_wording_options.locales.each do |locale|
|
|
12
|
-
LOGGER.debug("Starting export Properties wording for locale #{locale}")
|
|
13
|
-
locale_wording = export_wording_options.wording.translations_for(locale: locale)
|
|
14
|
-
return unless has_properties_wording?(locale_wording: locale_wording)
|
|
15
|
-
|
|
16
|
-
content = @properties_serializer.render(locale_wording: locale_wording)
|
|
17
|
-
@file_system_repository.create_directory(path: export_wording_options.platform_output_directory)
|
|
18
|
-
output_path = export_wording_options.platform_output_directory.join("#{locale}.properties")
|
|
19
|
-
@file_system_repository.write(content: content, path: output_path)
|
|
20
|
-
LOGGER.debug("#{locale}.properties done !")
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
def has_properties_wording?(locale_wording:)
|
|
27
|
-
locale_wording.has_singular_keys?
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Interactors
|
|
3
|
-
module Platforms
|
|
4
|
-
class ExportYAMLLocaleWording
|
|
5
|
-
def initialize
|
|
6
|
-
@yaml_serializer = Serializers::YAMLSerializer.new
|
|
7
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def call(export_wording_options:)
|
|
11
|
-
output_dir = export_wording_options.platform_output_directory
|
|
12
|
-
|
|
13
|
-
export_wording_options.locales.each do |locale|
|
|
14
|
-
LOGGER.debug("Starting export YAML wording for locale #{locale}")
|
|
15
|
-
locale_wording = export_wording_options.wording.translations_for(locale: locale)
|
|
16
|
-
content = @yaml_serializer.render(locale_wording: locale_wording)
|
|
17
|
-
next if content[locale].blank?
|
|
18
|
-
|
|
19
|
-
@file_system_repository.create_directory(path: output_dir)
|
|
20
|
-
@file_system_repository.write(content: content, path: output_dir.join("#{locale}.yml"))
|
|
21
|
-
LOGGER.debug("#{locale}.yml done !")
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Mappers
|
|
3
|
-
class CSVPathToWording
|
|
4
|
-
def map(csv_path:)
|
|
5
|
-
@headers = CSV.foreach(csv_path).first
|
|
6
|
-
return unless valid?(csv_path: csv_path)
|
|
7
|
-
translations = []
|
|
8
|
-
validator = Validators::KeyValidator.new
|
|
9
|
-
|
|
10
|
-
CSV.foreach(csv_path, headers: true, skip_blanks: true) do |row|
|
|
11
|
-
row_translations = map_row(row: row, locales: locales)
|
|
12
|
-
next if row_translations.blank?
|
|
13
|
-
|
|
14
|
-
current_key = row_translations.first.key
|
|
15
|
-
next if validator.has_warnings?(current_key)
|
|
16
|
-
|
|
17
|
-
translations.concat(row_translations)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
locale_wordings = translations.group_by(&:locale).map do |locale, group|
|
|
21
|
-
Entities::LocaleWording.new(locale: locale, translations: group)
|
|
22
|
-
end
|
|
23
|
-
Entities::Wording.new(locale_wordings: locale_wordings, default_locale: locales.first)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
|
|
28
|
-
def valid?(csv_path:)
|
|
29
|
-
File.exist?(csv_path) && has_key_column? && has_locales?
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def locales
|
|
33
|
-
@locales ||= compute_locales
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def compute_locales
|
|
37
|
-
return [] unless has_key_column? && key_column_index < @headers.size.pred
|
|
38
|
-
|
|
39
|
-
@headers.slice(key_column_index.succ..-1).compact.reject do |header|
|
|
40
|
-
header.to_s.include?(Constant::COMMENT_KEY_COLUMN_IDENTIFIER)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def has_locales?
|
|
45
|
-
locales.present?
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def has_key_column?
|
|
49
|
-
key_column_index.present?
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def key_column_index
|
|
53
|
-
@key_column_index ||= @headers.index(Constant::CSV_WORDING_KEYS_COLUMN)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def map_row(row:, locales:)
|
|
57
|
-
csv_wording_key = row.field(Constant::CSV_WORDING_KEYS_COLUMN)
|
|
58
|
-
return if csv_wording_key.blank?
|
|
59
|
-
|
|
60
|
-
key = Entities::Key.new(label: csv_wording_key)
|
|
61
|
-
locales.map do |locale|
|
|
62
|
-
comment_column_name = "#{Constant::COMMENT_KEY_COLUMN_IDENTIFIER} #{locale}"
|
|
63
|
-
Entities::Translation.new(
|
|
64
|
-
locale: locale,
|
|
65
|
-
key: key,
|
|
66
|
-
value: row.field(locale),
|
|
67
|
-
comment: row.field(comment_column_name)
|
|
68
|
-
)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Mappers
|
|
3
|
-
class TranslationGroupMapper
|
|
4
|
-
def initialize(translation_mapper: TranslationMapper.new)
|
|
5
|
-
@translation_mapper = translation_mapper
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def map(label:, translations:)
|
|
9
|
-
translation_view_models = translations.map { |translation| @translation_mapper.map(translation: translation) }
|
|
10
|
-
ViewModels::TranslationGroupViewModel.new(label: label, translation_view_models: translation_view_models)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Mappers
|
|
3
|
-
class TranslationMapper
|
|
4
|
-
def map(translation:)
|
|
5
|
-
ViewModels::TranslationViewModel.new(
|
|
6
|
-
label: translation.key.label,
|
|
7
|
-
key: key(translation: translation),
|
|
8
|
-
value: sanitize_value(value: translation.value),
|
|
9
|
-
comment: translation.comment
|
|
10
|
-
)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
protected
|
|
14
|
-
|
|
15
|
-
def sanitize_value(value:)
|
|
16
|
-
value
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def key(translation:)
|
|
22
|
-
if translation.key.plural?
|
|
23
|
-
translation.key.plural_key
|
|
24
|
-
elsif translation.key.adaptive?
|
|
25
|
-
translation.key.adaptive_key
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Mappers
|
|
3
|
-
class ValueRangeToWording
|
|
4
|
-
def map(value_range:)
|
|
5
|
-
values = value_range.values
|
|
6
|
-
analyze_header(first_row: values.first)
|
|
7
|
-
return unless valid_header?
|
|
8
|
-
|
|
9
|
-
translations = map_rows(values: values)
|
|
10
|
-
locale_wordings = translations.group_by(&:locale).map do |locale, group|
|
|
11
|
-
Entities::LocaleWording.new(locale: locale, translations: group)
|
|
12
|
-
end
|
|
13
|
-
Entities::Wording.new(locale_wordings: locale_wordings, default_locale: @locale_mapping.keys.first)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def map_rows(values:)
|
|
19
|
-
translations = []
|
|
20
|
-
validator = Validators::KeyValidator.new
|
|
21
|
-
|
|
22
|
-
values[1..-1].each do |row|
|
|
23
|
-
row_translations = map_row(row: row)
|
|
24
|
-
next if row_translations.blank?
|
|
25
|
-
|
|
26
|
-
current_key = row_translations.first.key
|
|
27
|
-
next if validator.has_warnings?(current_key)
|
|
28
|
-
|
|
29
|
-
translations.concat(row_translations)
|
|
30
|
-
end
|
|
31
|
-
translations
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def analyze_header(first_row:)
|
|
35
|
-
@header = first_row
|
|
36
|
-
@key_index = first_row.index(Constant::CSV_WORDING_KEYS_COLUMN)
|
|
37
|
-
@locale_mapping = {}
|
|
38
|
-
first_row[@key_index.succ..-1].each_index do |relative_index|
|
|
39
|
-
absolute_index = @key_index.succ + relative_index
|
|
40
|
-
next if first_row[absolute_index].blank? || first_row[absolute_index].include?(Constant::COMMENT_KEY_COLUMN_IDENTIFIER)
|
|
41
|
-
@locale_mapping[first_row[absolute_index]] = { key_index: absolute_index }
|
|
42
|
-
comment_column_name = "#{Constant::COMMENT_KEY_COLUMN_IDENTIFIER} #{first_row[absolute_index]}"
|
|
43
|
-
@locale_mapping[first_row[absolute_index]][:comment_index] = first_row.index(comment_column_name)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def map_row(row:)
|
|
48
|
-
csv_wording_key = row[@key_index]
|
|
49
|
-
return if csv_wording_key.blank?
|
|
50
|
-
key = Entities::Key.new(label: csv_wording_key)
|
|
51
|
-
@locale_mapping.map do |locale, index_mapping|
|
|
52
|
-
comment = index_mapping[:comment_index].nil? ? nil : row[index_mapping[:comment_index]]
|
|
53
|
-
Entities::Translation.new(
|
|
54
|
-
locale: locale,
|
|
55
|
-
key: key,
|
|
56
|
-
value: row[index_mapping[:key_index]],
|
|
57
|
-
comment: comment
|
|
58
|
-
)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def valid_header?
|
|
63
|
-
@key_index.present? || @locale_mapping.keys.size.positive?
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Repositories
|
|
3
|
-
class GSheetsRepository
|
|
4
|
-
SCOPES = [Google::Apis::SheetsV4::AUTH_SPREADSHEETS_READONLY]
|
|
5
|
-
ROWS_MAJOR_DIMENSION = 'ROWS'.freeze
|
|
6
|
-
SPREADSHEET_APPLICATION_NAME = 'ad_localize'.freeze
|
|
7
|
-
|
|
8
|
-
def initialize
|
|
9
|
-
@service = Google::Apis::SheetsV4::SheetsService.new
|
|
10
|
-
@service.client_options.application_name = SPREADSHEET_APPLICATION_NAME
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def get_sheets_values(g_spreadsheet_options:)
|
|
14
|
-
configure(json_configuration: g_spreadsheet_options.service_account_config) if @service.authorization.nil?
|
|
15
|
-
spreadsheet = @service.get_spreadsheet(g_spreadsheet_options.spreadsheet_id)
|
|
16
|
-
if g_spreadsheet_options.export_all
|
|
17
|
-
spreadsheet.sheets.map { |sheet| get_sheet_values(spreadsheet_id: g_spreadsheet_options.spreadsheet_id, sheet: sheet) }
|
|
18
|
-
elsif g_spreadsheet_options.sheet_ids.nil? || g_spreadsheet_options.sheet_ids.size.zero?
|
|
19
|
-
spreadsheet.sheets[0..0].map { |sheet| get_sheet_values(spreadsheet_id: g_spreadsheet_options.spreadsheet_id, sheet: sheet) }
|
|
20
|
-
else
|
|
21
|
-
spreadsheet.sheets.select do |sheet|
|
|
22
|
-
g_spreadsheet_options.sheet_ids.include?(sheet.properties.sheet_id.to_s)
|
|
23
|
-
end.map do |sheet|
|
|
24
|
-
get_sheet_values(spreadsheet_id: g_spreadsheet_options.spreadsheet_id, sheet: sheet)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def configure(json_configuration:)
|
|
32
|
-
raise ArgumentError.new('No service account configuration') if json_configuration.blank?
|
|
33
|
-
json_key_io = StringIO.new(json_configuration)
|
|
34
|
-
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: json_key_io, scope: SCOPES)
|
|
35
|
-
@service.authorization = authorizer
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def get_sheet_values(spreadsheet_id:, sheet:)
|
|
39
|
-
range = sheet.properties.title
|
|
40
|
-
@service.get_spreadsheet_values(spreadsheet_id, range, major_dimension: ROWS_MAJOR_DIMENSION)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Requests
|
|
3
|
-
class ExportWordingOptions
|
|
4
|
-
def initialize(wording:, platform_output_directory:, locales: [], bypass_empty_values: false, csv_paths: [])
|
|
5
|
-
@wording = wording
|
|
6
|
-
@locales = locales
|
|
7
|
-
@platform_output_directory = platform_output_directory
|
|
8
|
-
@bypass_empty_values = bypass_empty_values
|
|
9
|
-
@csv_paths = csv_paths
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
attr_reader(
|
|
13
|
-
:wording,
|
|
14
|
-
:platform_output_directory,
|
|
15
|
-
:bypass_empty_values,
|
|
16
|
-
:locales
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
attr_accessor(
|
|
20
|
-
:csv_paths
|
|
21
|
-
)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Requests
|
|
3
|
-
class GSpreadsheetOptions
|
|
4
|
-
attr_accessor(
|
|
5
|
-
:spreadsheet_id,
|
|
6
|
-
:sheet_ids,
|
|
7
|
-
:export_all,
|
|
8
|
-
:service_account_config
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
def initialize(**args)
|
|
12
|
-
@spreadsheet_id = args[:spreadsheet_id]
|
|
13
|
-
@sheet_ids = Array(args[:sheet_ids])
|
|
14
|
-
@export_all = args[:export_all] || false
|
|
15
|
-
@service_account_config = args[:service_account_config].presence
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def valid?
|
|
19
|
-
(spreadsheet_id && !export_all) || (spreadsheet_id && service_account_config.present?)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def public_download_urls
|
|
23
|
-
return [] if @service_account_config
|
|
24
|
-
if @sheet_ids.size.zero?
|
|
25
|
-
[public_download_url(sheet_id: nil)]
|
|
26
|
-
else
|
|
27
|
-
@sheet_ids.map { |sheet_id| public_download_url(sheet_id: sheet_id) }
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def has_multiple_sheets?
|
|
32
|
-
export_all || @sheet_ids.size > 1
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
def public_download_url(sheet_id:)
|
|
38
|
-
query_id = sheet_id.blank? ? "id=#{@spreadsheet_id}" : "gid=#{sheet_id}"
|
|
39
|
-
"https://docs.google.com/spreadsheets/d/#{@spreadsheet_id}/export?format=csv&#{query_id}"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def valid_export_all_config
|
|
43
|
-
export_all && service_account_config.present?
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Requests
|
|
3
|
-
class MergePolicy
|
|
4
|
-
REPLACE_POLICY = 'replace'.freeze
|
|
5
|
-
KEEP_POLICY = 'keep'.freeze
|
|
6
|
-
MERGE_POLICIES = [KEEP_POLICY, REPLACE_POLICY]
|
|
7
|
-
DEFAULT_POLICY = KEEP_POLICY
|
|
8
|
-
|
|
9
|
-
attr_reader(:policy)
|
|
10
|
-
|
|
11
|
-
def initialize(policy:)
|
|
12
|
-
@policy = policy
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def keep?
|
|
16
|
-
@policy == KEEP_POLICY
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def replace?
|
|
20
|
-
@policy == REPLACE_POLICY
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def valid?
|
|
24
|
-
@policy.present? && MERGE_POLICIES.include?(@policy)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Serializers
|
|
3
|
-
module WithTemplate
|
|
4
|
-
TEMPLATES_DIRECTORY = __dir__ + "/../templates"
|
|
5
|
-
|
|
6
|
-
def render(locale_wording:)
|
|
7
|
-
hash_binding = hash_binding(locale_wording: locale_wording)
|
|
8
|
-
return unless hash_binding
|
|
9
|
-
render_template(template_path: template_path, hash_binding: hash_binding)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def render_template(template_path:, hash_binding:)
|
|
13
|
-
template = File.read(template_path)
|
|
14
|
-
renderer = ERB.new(template, trim_mode: '-')
|
|
15
|
-
renderer.result_with_hash(hash_binding)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module Validators
|
|
3
|
-
class KeyValidator
|
|
4
|
-
|
|
5
|
-
def initialize
|
|
6
|
-
@existing_key_for_label = {}
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def has_warnings?(current_key)
|
|
10
|
-
current_label = current_key.label
|
|
11
|
-
existing_key = @existing_key_for_label[current_label]
|
|
12
|
-
|
|
13
|
-
has_warnings = false
|
|
14
|
-
|
|
15
|
-
unless existing_key.nil?
|
|
16
|
-
existing_plural_key = existing_key.label == current_key.label && existing_key.plural? && current_key.singular?
|
|
17
|
-
existing_singular_key = existing_key.label == current_key.label && existing_key.singular? && current_key.plural?
|
|
18
|
-
is_same_key = existing_key.same_as?(key: current_key)
|
|
19
|
-
LOGGER.warn "A plural value already exist for key '#{current_label}'. Remove duplicates." if existing_plural_key
|
|
20
|
-
LOGGER.warn "A singular value already exist for key '#{current_label}'. Remove duplicates." if existing_singular_key
|
|
21
|
-
LOGGER.warn "Some values already exist for key '#{current_label}'. Remove duplicates." if is_same_key
|
|
22
|
-
has_warnings = is_same_key || existing_plural_key || existing_singular_key
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
@existing_key_for_label[current_label] = current_key
|
|
26
|
-
|
|
27
|
-
has_warnings
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module ViewModels
|
|
3
|
-
class TranslationGroupViewModel
|
|
4
|
-
attr_reader(
|
|
5
|
-
:label,
|
|
6
|
-
:translation_view_models
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
def initialize(label:, translation_view_models:)
|
|
10
|
-
@label = label
|
|
11
|
-
@translation_view_models = translation_view_models
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def has_translations?
|
|
15
|
-
(translation_view_models || []).any?(&:has_value?)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module AdLocalize
|
|
2
|
-
module ViewModels
|
|
3
|
-
class TranslationViewModel
|
|
4
|
-
attr_reader(
|
|
5
|
-
:label,
|
|
6
|
-
:key,
|
|
7
|
-
:value,
|
|
8
|
-
:comment
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
def initialize(label:, key:, value:, comment:)
|
|
12
|
-
@label = label
|
|
13
|
-
@key = key
|
|
14
|
-
@value = value
|
|
15
|
-
@comment = comment
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def has_value?
|
|
19
|
-
value.present?
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|