Skip to content

Instantly share code, notes, and snippets.

@WaKeMaTTa
Created August 12, 2022 17:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WaKeMaTTa/f854a210bec68a2f524d052f9dc28083 to your computer and use it in GitHub Desktop.
Save WaKeMaTTa/f854a210bec68a2f524d052f9dc28083 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'yaml'
if Gem::Version.new(Psych::LIBYAML_VERSION) < Gem::Version.new('0.2.5')
warn "Your libyaml library is outdated: please upgrade to >= 0.2.5.\n" \
"The generated YAML will include output trailing spaces for empty scalar nodes, whereas " \
"Phrase doesn't include them."
end
# Method to "deep sort" keys in a Hash (i.e. recursively), the way that Phrase would do.
#
# The "translation ordering on export" setting has been set to "Default" in Phrase. This is
# translated as MySQL `utf8mb4_general_ci` collation being used. (Whereas the "Natural" option
# is translated as `utf8mb4_unicode_ci` collation).
#
# This collation does not compare Strings exactly the same way as Ruby does. Especially, in this
# collation, the `_` character is considered to be **before** letters, whereas in Ruby it's
# considered as **after** (cf ASCII RFC https://www.rfc-editor.org/rfc/rfc20.html#page-2).
#
# in Ruby (and more generally in ASCII):
#
# '_' > 'a' => false
#
# in SQL:
#
# SELECT '_' > 'a' COLLATE utf8mb4_general_ci => 1
#
# To mitigate this difference, we replace the `_` character by `|`, which is considered as before
# letters, in both Ruby and `utf8mb4_general_ci` MySQL collation (`'|' > 'a'` is true).
def sort_hash_alphabetically(hash)
hash.sort_by do |(key, _value)|
key.tr('_', '|')
end.to_h.transform_values! do |v|
v.is_a?(Hash) ? sort_hash_alphabetically(v) : v
end
end
APP_ROOT = File.expand_path('..', __dir__)
def locale_files
Dir.glob("#{APP_ROOT}/config/locales/**/*.yml")
end
def format_phrase(data)
YAML.dump(sort_hash_alphabetically(data))
end
def check_the_format(fix: false)
error = false
locale_files.each do |filepath|
source = File.read(filepath)
formatted_source = format_phrase(YAML.load(source))
if formatted_source != source
error = true
msg = fix ? 'is corrected' : 'not properly formatted'
puts "#{filepath.gsub(/^#{APP_ROOT}/, '.')} #{msg}"
end
File.write(filepath, formatted_source) if fix
end
if error
exit(1)
else
puts "Locale files are properly formatted"
exit
end
end
require 'optparse'
OptionParser.new do |opts|
opts.banner = "Usage: bin/format_phrase [options]"
opts.on("-f", "--fix", "Updates the locale files to Phrase format (default)") do
check_the_format(fix: true)
end
opts.on("-c", "--check", "Checks that locale files are properly formatted") do
check_the_format
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!
check_the_format(fix: true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment