Skip to content

Instantly share code, notes, and snippets.

@cdlm
Last active August 29, 2015 14:07
Show Gist options
  • Save cdlm/96bc80381bfd46cc7ead to your computer and use it in GitHub Desktop.
Save cdlm/96bc80381bfd46cc7ead to your computer and use it in GitHub Desktop.
Scripts to help translating the Codeless Code (https://github.com/alessandro1997/the-codeless-code).

Helpers for translating the Codeless Code

The scripts are parameterized via environment variables (direnv), notably $CODELESS_TRANSLATION (see the help text in translate-case.rb).

  • translate-case.rb: automates the initial copy of cases from Qi's original version to a translation directory, and helps opening cases from a given translation.

  • pre-commit.rb: git hook to check for french spacing conventions (non-breaking spaces before double punctuation signs and inside quotes.

#!/usr/bin/env ruby
require 'cgi'
input = ARGV.empty? ? $stdin : StringIO(ARGV.join(' '))
input.each_line do |line|
puts CGI::escape(line.chomp)
end
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
#
# Checks staged contents of changed files for normal spaces left where french
# typography rules would require a non-breaking space:
# - inside guillemots « and »
# - before double punctuation signs :;!?
exit if ENV['CODELESS_TRANSLATION'].nil?
begin
require 'paint'
Paint::SHORTCUTS[:highlight] = {
file: Paint.color(:blue),
warn: Paint.color(nil, :red)
}
include Paint::Highlight
rescue LoadError
def no_paint(s) s end
alias file no_paint
alias warn no_paint
end
FILE_GLOB = "the-codeless-code/#{ENV['CODELESS_TRANSLATION']}/case-*.txt"
HEADER_PATTERN = /^([[:alnum:]]|\.)+: /
NON_NBSP = /[^\u00A0]/ # anything but a  
ENTITY = /(?<entity>&[^\s;]+;)/
BAD_AFTER = /(?<=«)#{NON_NBSP}/
BAD_BEFORE = /#{NON_NBSP}(?=[:;?!»])/
PATTERN = Regexp.union ENTITY, BAD_BEFORE, BAD_AFTER
def files_to_check
IO.popen(%w(git diff --cached --name-only --diff-filter=ACM)) do |io|
io.each_line.map(&:chomp).select { |each| File.fnmatch? FILE_GLOB, each }
end
end
def staged_contents filename, &block
IO.popen(['git', 'show', ":#{filename}"]) do |io|
io.each_line.with_index &block
end
end
problems_in_total = 0
files_to_check.each do |name|
in_header = true
first_in_file = true
staged_contents(name) do |line,num|
line.chomp!
next if in_header && HEADER_PATTERN === line
in_header = false
problems_on_line = 0
line = line.gsub PATTERN do
match = Regexp.last_match
if match[:entity].nil?
problems_on_line += 1
warn(match)
else
match
end
end
unless problems_on_line.zero?
puts file(name) if first_in_file
puts " #{num + 1}: #{line}"
problems_in_total += problems_on_line
first_in_file = false
end
end
end
if problems_in_total > 0
puts "\n#{problems_in_total} occurrences of bad or missing spaces near punctuation"
exit 42
end
#!/usr/bin/env ruby
# See help text below or run with --help for docs
require 'cri' # gem install cri
require 'fileutils'
require 'pathname'
require 'tempfile'
def translation_dir translation
d = ROOT.join translation
d if d.directory? or raise "No such translation #{translation}"
end
def case_file case_num, translation
translation_dir(translation).join "case-#{case_num}.txt"
end
def available? case_num, translation
case_file(case_num, translation).exist?
end
def case_numbers translation
cases = Pathname.glob translation_dir(translation).join('case-[0-9]*.txt')
cases.map { |each| /(\d+)\.txt/.match(each.to_path)[1].to_i }.sort
end
def untranslated_cases src, dest
case_numbers(src) - case_numbers(dest)
end
def root_command
Cri::Command.define do
name NAME
usage "#{NAME} [case] [src=#{DEFAULT_SOURCE}] [dest=#{DEFAULT_DESTINATION}]"
summary "copies a case before starting its translation"
description <<EOS
Copies selected case from an authoritative translation (src) to an in-progress translation (dest).
The case can be specified either by its explicit number, or by one of the following keywords:
current (latest translated case), or
next/last/random (among the cases not yet in the destination translation).
Environment variables:
CODELESS_TRANSLATION
-- Name of the translation directory to copy cases to.
CODELESS_SOURCE
-- Override the default source translation (en-qi).
CODELESS_BRANCH
-- Format string used to name branches; %{translation} and %{case} will be expanded.
EOS
flag :h, :help, "show command usage" do |_, cmd|
puts cmd.help
exit
end
flag nil, :dryrun, "only say what would be done"
flag nil, :overwrite, "copy even if destination case exists"
flag :e, :edit, "open case in $EDITOR"
flag :b, :branch, "checkout branch from master (named after $CODELESS_BRANCH)"
flag :a, :add, "add case to git"
run do |opts, args, cmd|
selection = args[0] || DEFAULT_SELECTION
src = args[1] || DEFAULT_SOURCE
dest = args[2] || DEFAULT_DESTINATION || raise(StandardError, "No destination translation given, please set $CODELESS_TRANSLATION")
language, translator = dest.split('-')
case_num = case selection
when /^\d+$/ then args[0].to_i
when /^c(ur(rent)?)?$/ then case_numbers(dest).last
when /^n(ext)?$/ then untranslated_cases(src, dest).first
when /^l(a(te)?st)?$/ then untranslated_cases(src, dest).last
when /^r(and(om)?)?$/ then untranslated_cases(src, dest).sample
else raise "Invalid case selector #{selection}"
end
raise "No available cases to translate from #{src} to #{dest}" if case_num.nil?
raise "No case ##{case_num} in translation #{src}" unless available?(case_num, src)
raise "Case ##{case_num} already exists in translation #{dest}" if available?(case_num, dest) unless opts[:overwrite] || opts[:edit]
if opts[:branch]
branch = (BRANCH_FORMAT) % { translation: dest, case: case_num }
exists = system 'git', 'show-branch', branch
system 'git', 'checkout', *(exists ? [branch] : ['-b', branch, 'master']) unless opts[:dryrun]
end
unless available?(case_num, dest) && opts[:edit]
$stderr.puts "Copying case ##{case_num} (#{src} -> #{dest})"
dest_path = case_file(case_num, dest)
unless opts[:dryrun]
FileUtils.cp case_file(case_num, src), dest_path
system 'git', 'add', dest_path.to_path if opts[:add]
Tempfile.open(dest) do |tmp|
tmp.write <<EOF
Lang: #{language}
Translator: #{translator}
EOF
tmp.write File.read(dest_path)
File.rename tmp, dest_path
end
end
puts dest_path.expand_path.relative_path_from(Pathname.pwd)
end
if opts[:edit]
exec ENV['EDITOR'], case_file(case_num, dest).to_path unless opts[:dryrun]
end
end
end
end
# ...and here we go
begin
NAME = File.basename(__FILE__)
ROOT = Pathname.new(`git rev-parse --show-cdup`.strip).join('the-codeless-code')
DEFAULT_SELECTION = ENV['CODELESS_SELECTION'] || 'next'
DEFAULT_SOURCE = ENV['CODELESS_SOURCE'] || 'en-qi'
DEFAULT_DESTINATION = ENV['CODELESS_TRANSLATION']
BRANCH_FORMAT = ENV['CODELESS_BRANCH'] || '%{translation}-%{case}'
root_command.run(ARGV)
rescue StandardError => e
puts e.message
exit 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment