ad_localize 4.1.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +70 -15
- data/Gemfile +1 -0
- data/Gemfile.lock +63 -61
- data/README.md +37 -10
- data/Rakefile +1 -0
- data/ad_localize.gemspec +14 -13
- data/bin/console +1 -1
- 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 +27 -18
- 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 -21
- data/lib/ad_localize/option_handler.rb +50 -26
- 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 +97 -53
- 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 -11
- data/lib/ad_localize/serializers/localizable_stringsdict_serializer.rb +12 -19
- 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 -34
- metadata +86 -69
- 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 -43
- data/lib/ad_localize/interactors/export_csv_files.rb +0 -17
- data/lib/ad_localize/interactors/export_g_spreadsheet.rb +0 -59
- data/lib/ad_localize/interactors/platforms/export_android_locale_wording.rb +0 -43
- data/lib/ad_localize/interactors/platforms/export_csv_locale_wording.rb +0 -25
- data/lib/ad_localize/interactors/platforms/export_ios_locale_wording.rb +0 -66
- 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 -33
- 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/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,24 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Entities
|
3
|
-
class Wording
|
4
|
-
attr_reader(:default_locale, :locale_wordings)
|
5
|
-
|
6
|
-
def initialize(locale_wordings:, default_locale:)
|
7
|
-
@locale_wordings = locale_wordings
|
8
|
-
@default_locale = default_locale
|
9
|
-
end
|
10
|
-
|
11
|
-
def translations_for(locale:)
|
12
|
-
@locale_wordings.find { |locale_wording| locale_wording.locale == locale }
|
13
|
-
end
|
14
|
-
|
15
|
-
def locales
|
16
|
-
@locale_wordings.map(&:locale)
|
17
|
-
end
|
18
|
-
|
19
|
-
def default_locale?(locale:)
|
20
|
-
locale == @default_locale
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Interactors
|
3
|
-
class ExecuteExportRequest
|
4
|
-
def initialize(csv_path_to_wording: nil, value_range_to_wording: nil)
|
5
|
-
@csv_path_to_wording = csv_path_to_wording
|
6
|
-
@value_range_to_wording = value_range_to_wording
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(export_request:)
|
10
|
-
export_request.verbose? ? LOGGER.debug! : LOGGER.info!
|
11
|
-
print_export_request(export_request: export_request) if export_request.verbose?
|
12
|
-
LOGGER.debug("Checking request validity")
|
13
|
-
return unless export_request.valid?
|
14
|
-
if export_request.has_csv_files?
|
15
|
-
ExportCSVFiles.new(csv_path_to_wording: @csv_path_to_wording).call(export_request: export_request)
|
16
|
-
elsif export_request.has_g_spreadsheet_options?
|
17
|
-
ExportGSpreadsheet.new(value_range_to_wording: @value_range_to_wording).call(export_request: export_request)
|
18
|
-
end
|
19
|
-
LOGGER.debug("End of export request execution")
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def print_export_request(export_request:)
|
25
|
-
LOGGER.debug("Export Request info")
|
26
|
-
LOGGER.debug("locales : #{export_request.locales.to_sentence}")
|
27
|
-
LOGGER.debug("platforms : #{export_request.platforms.to_sentence}")
|
28
|
-
LOGGER.debug("output_path : #{export_request.output_path}")
|
29
|
-
LOGGER.debug("verbose : #{export_request.verbose}")
|
30
|
-
LOGGER.debug("merge_policy : #{export_request.merge_policy&.policy}")
|
31
|
-
LOGGER.debug("csv_paths : #{export_request.csv_paths.to_sentence}")
|
32
|
-
if export_request.has_g_spreadsheet_options?
|
33
|
-
g_options = export_request.g_spreadsheet_options
|
34
|
-
LOGGER.debug("spreadsheet_id : #{g_options.spreadsheet_id}")
|
35
|
-
LOGGER.debug("sheet_ids : #{g_options.sheet_ids.to_sentence}")
|
36
|
-
LOGGER.debug("export_all: #{g_options.export_all}")
|
37
|
-
LOGGER.debug("service_account: #{g_options.service_account_config.present?}")
|
38
|
-
end
|
39
|
-
LOGGER.debug("End Export Request info")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Interactors
|
3
|
-
class ExportCSVFiles
|
4
|
-
def initialize(csv_path_to_wording: nil)
|
5
|
-
@csv_path_to_wording = csv_path_to_wording.presence || Mappers::CSVPathToWording.new
|
6
|
-
@merge_wordings = MergeWordings.new
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(export_request:)
|
10
|
-
LOGGER.debug("Starting export csv files : #{export_request.csv_paths.to_sentence}")
|
11
|
-
wordings = export_request.csv_paths.map { |csv_path| @csv_path_to_wording.map(csv_path: csv_path) }
|
12
|
-
wording = @merge_wordings.call(wordings: wordings.compact, merge_policy: export_request.merge_policy)
|
13
|
-
ExportWording.new.call(export_request: export_request, wording: wording)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Interactors
|
3
|
-
class ExportGSpreadsheet
|
4
|
-
def initialize(value_range_to_wording: nil)
|
5
|
-
@value_range_to_wording = value_range_to_wording.presence || Mappers::ValueRangeToWording.new
|
6
|
-
@g_sheets_repository = Repositories::GSheetsRepository.new
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(export_request:)
|
10
|
-
LOGGER.debug("Starting export google spreadsheet")
|
11
|
-
if export_request.g_spreadsheet_options.service_account_config
|
12
|
-
export_with_service_account(export_request: export_request)
|
13
|
-
else
|
14
|
-
export_without_service_account(export_request: export_request)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def export_with_service_account(export_request:)
|
21
|
-
LOGGER.debug("Using service account")
|
22
|
-
value_ranges = @g_sheets_repository.get_sheets_values(g_spreadsheet_options: export_request.g_spreadsheet_options)
|
23
|
-
wordings = value_ranges.map { |value_range| @value_range_to_wording.map(value_range: value_range) }
|
24
|
-
wording = MergeWordings.new.call(wordings: wordings.compact, merge_policy: export_request.merge_policy)
|
25
|
-
ExportWording.new.call(export_request: export_request, wording: wording)
|
26
|
-
end
|
27
|
-
|
28
|
-
def export_without_service_account(export_request:)
|
29
|
-
LOGGER.debug("Using direct access to spreadsheet")
|
30
|
-
downloaded_files = export_request.g_spreadsheet_options.public_download_urls.map do |sheet_download_url|
|
31
|
-
download_public_sheet(url: sheet_download_url)
|
32
|
-
end
|
33
|
-
export_request.csv_paths = downloaded_files.map(&:path)
|
34
|
-
if export_request.has_csv_files?
|
35
|
-
ExportCSVFiles.new.call(export_request: export_request)
|
36
|
-
elsif export_request.has_empty_files?
|
37
|
-
# When downloading an empty spreadsheet, the content type of the downloaded file is "inode/x-empty"
|
38
|
-
LOGGER.warn("Your spreadsheet is empty. Add content and retry.")
|
39
|
-
else
|
40
|
-
# When shared configuration is misconfigured, the content type of the downloaded file is "text/html"
|
41
|
-
LOGGER.error("Invalid export request. Check the spreadsheet share configuration")
|
42
|
-
end
|
43
|
-
downloaded_files.select { |downloaded_file| File.exist?(downloaded_file.path) }.each do |downloaded_file|
|
44
|
-
downloaded_file.close
|
45
|
-
downloaded_file.unlink
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def download_public_sheet(url:)
|
50
|
-
tempfile = Tempfile.new
|
51
|
-
URI.open(url) do |uri_io|
|
52
|
-
tempfile.write uri_io.read
|
53
|
-
tempfile.rewind
|
54
|
-
end
|
55
|
-
tempfile
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Interactors
|
3
|
-
module Platforms
|
4
|
-
class ExportAndroidLocaleWording
|
5
|
-
STRINGS_FILENAME = 'strings.xml'.freeze
|
6
|
-
LOCALE_DIRECTORY_CONVENTION = "values%{locale_suffix}".freeze
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@strings_serializer = Serializers::StringsSerializer.new
|
10
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
11
|
-
end
|
12
|
-
|
13
|
-
def call(wording:, locale:, platform_dir:)
|
14
|
-
LOGGER.debug("Starting export Android wording for locale #{locale}")
|
15
|
-
locale_wording = wording.translations_for(locale: locale)
|
16
|
-
return unless has_android_wording?(locale_wording: locale_wording)
|
17
|
-
|
18
|
-
output_dir = compute_output_dir(wording: wording, locale: locale, platform_dir: platform_dir)
|
19
|
-
@file_system_repository.create_directory(path: output_dir)
|
20
|
-
|
21
|
-
content = @strings_serializer.render(locale_wording: locale_wording)
|
22
|
-
@file_system_repository.write(content: content, path: output_dir.join(STRINGS_FILENAME))
|
23
|
-
LOGGER.debug("#{STRINGS_FILENAME} done !")
|
24
|
-
end
|
25
|
-
|
26
|
-
def should_export_locale_by_locale?
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def has_android_wording?(locale_wording:)
|
33
|
-
locale_wording.has_singular_keys? || locale_wording.has_plural_keys?
|
34
|
-
end
|
35
|
-
|
36
|
-
def compute_output_dir(wording:, locale:, platform_dir:)
|
37
|
-
locale_suffix = wording.default_locale?(locale: locale) ? '' : "-#{locale}"
|
38
|
-
platform_dir.join(LOCALE_DIRECTORY_CONVENTION % { locale_suffix: locale_suffix })
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module AdLocalize
|
2
|
-
module Interactors
|
3
|
-
module Platforms
|
4
|
-
class ExportCSVLocaleWording
|
5
|
-
def initialize
|
6
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(export_request:, platform_dir:)
|
10
|
-
LOGGER.debug("Starting export CSV wording")
|
11
|
-
@file_system_repository.create_directory(path: platform_dir)
|
12
|
-
export_request.csv_paths.each_with_index do |csv_path, i|
|
13
|
-
file = File.basename("localization_#{i}.csv")
|
14
|
-
FileUtils.cp(csv_path, platform_dir.join(file.to_s))
|
15
|
-
end
|
16
|
-
LOGGER.debug("CSV wording export done !")
|
17
|
-
end
|
18
|
-
|
19
|
-
def should_export_locale_by_locale?
|
20
|
-
false
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,66 +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
|
-
@localizable_strings_serializer = Serializers::LocalizableStringsSerializer.new
|
13
|
-
@localizable_stringsdict_serializer = Serializers::LocalizableStringsdictSerializer.new
|
14
|
-
@file_system_repository = Repositories::FileSystemRepository.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def call(wording:, locale:, platform_dir:)
|
18
|
-
LOGGER.debug("Starting export iOS wording for locale #{locale}")
|
19
|
-
locale_wording = wording.translations_for(locale: locale)
|
20
|
-
return unless has_ios_wording?(locale_wording: locale_wording)
|
21
|
-
|
22
|
-
output_dir = platform_dir.join(LOCALE_DIRECTORY_CONVENTION % { locale: locale })
|
23
|
-
@file_system_repository.create_directory(path: output_dir)
|
24
|
-
|
25
|
-
export_info_plist(locale_wording: locale_wording, output_dir: output_dir)
|
26
|
-
export_localizable_strings(locale_wording: locale_wording, output_dir: output_dir)
|
27
|
-
export_localizable_stringsdict(locale_wording: locale_wording, output_dir: output_dir)
|
28
|
-
end
|
29
|
-
|
30
|
-
def should_export_locale_by_locale?
|
31
|
-
true
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def has_ios_wording?(locale_wording:)
|
37
|
-
locale_wording.has_info_plist_keys? ||
|
38
|
-
locale_wording.has_singular_keys? ||
|
39
|
-
locale_wording.has_plural_keys? ||
|
40
|
-
locale_wording.has_adaptive_keys?
|
41
|
-
end
|
42
|
-
|
43
|
-
def export_info_plist(locale_wording:, output_dir:)
|
44
|
-
return unless locale_wording.has_info_plist_keys?
|
45
|
-
content = @info_plist_serializer.render(locale_wording: locale_wording)
|
46
|
-
@file_system_repository.write(content: content, path: output_dir.join(INFO_PLIST_FILENAME))
|
47
|
-
LOGGER.debug("#{INFO_PLIST_FILENAME} done !")
|
48
|
-
end
|
49
|
-
|
50
|
-
def export_localizable_strings(locale_wording:, output_dir:)
|
51
|
-
return unless locale_wording.has_singular_keys?
|
52
|
-
content = @localizable_strings_serializer.render(locale_wording: locale_wording)
|
53
|
-
@file_system_repository.write(content: content, path: output_dir.join(LOCALIZABLE_STRINGS_FILENAME))
|
54
|
-
LOGGER.debug("#{LOCALIZABLE_STRINGS_FILENAME} done !")
|
55
|
-
end
|
56
|
-
|
57
|
-
def export_localizable_stringsdict(locale_wording:, output_dir:)
|
58
|
-
return unless locale_wording.has_plural_keys? || locale_wording.has_adaptive_keys?
|
59
|
-
content = @localizable_stringsdict_serializer.render(locale_wording: locale_wording)
|
60
|
-
@file_system_repository.write(content: content, path: output_dir.join(LOCALIZABLE_STRINGSDICT_FILENAME))
|
61
|
-
LOGGER.debug("#{LOCALIZABLE_STRINGSDICT_FILENAME} done !")
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
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(wording:, locale:, platform_dir:)
|
11
|
-
LOGGER.debug("Starting export JSON wording for locale #{locale}")
|
12
|
-
locale_wording = wording.translations_for(locale: locale)
|
13
|
-
content = @json_serializer.render(locale_wording: locale_wording)
|
14
|
-
return if content[locale].blank?
|
15
|
-
|
16
|
-
@file_system_repository.create_directory(path: platform_dir)
|
17
|
-
@file_system_repository.write(content: content, path: platform_dir.join("#{locale}.json"))
|
18
|
-
LOGGER.debug("#{locale}.json done !")
|
19
|
-
end
|
20
|
-
|
21
|
-
def should_export_locale_by_locale?
|
22
|
-
true
|
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,33 +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(wording:, locale:, platform_dir:)
|
11
|
-
LOGGER.debug("Starting export Properties wording for locale #{locale}")
|
12
|
-
locale_wording = wording.translations_for(locale: locale)
|
13
|
-
return unless has_properties_wording?(locale_wording: locale_wording)
|
14
|
-
|
15
|
-
content = @properties_serializer.render(locale_wording: locale_wording)
|
16
|
-
@file_system_repository.create_directory(path: platform_dir)
|
17
|
-
@file_system_repository.write(content: content, path: platform_dir.join("#{locale}.properties"))
|
18
|
-
LOGGER.debug("#{locale}.properties done !")
|
19
|
-
end
|
20
|
-
|
21
|
-
def should_export_locale_by_locale?
|
22
|
-
true
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def has_properties_wording?(locale_wording:)
|
28
|
-
locale_wording.has_singular_keys?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
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(wording:, locale:, platform_dir:)
|
11
|
-
LOGGER.debug("Starting export YAML wording for locale #{locale}")
|
12
|
-
locale_wording = wording.translations_for(locale: locale)
|
13
|
-
content = @yaml_serializer.render(locale_wording:locale_wording)
|
14
|
-
return if content[locale].blank?
|
15
|
-
|
16
|
-
@file_system_repository.create_directory(path: platform_dir)
|
17
|
-
@file_system_repository.write(content: content, path: platform_dir.join("#{locale}.yml"))
|
18
|
-
LOGGER.debug("#{locale}.yml done !")
|
19
|
-
end
|
20
|
-
|
21
|
-
def should_export_locale_by_locale?
|
22
|
-
true
|
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
|