1#!/usr/bin/env ruby 2# 3# Word wrap Frogatto po file msgstrs so that lines fit on the game screen according to 4# glyph data defined in configuration files. 5# 6# Usage 7# 8# utils/word_wrap_po.rb LANGUAGE 9# 10# LANGUAGE is the base name of the po file, for example zh_CN 11# 12# The script ensures that line breaks occur only at "legal" positions, e.g. never before 13# closing punctuations. However it does not try to break at the most appealing positions. 14# 15# It ignores messages containing existing line breaks or {markup}, and messages 16# from CHANGELOG, METADATA, and titlescreen files. 17# 18# Parts of the po file which the script "ignores" may still be modified, including 19# msgids. However there should be only po metadata and formatting changes and the 20# interpreted msgids and msgstrs remain the same. 21# 22# This script requires Ruby and the gems ffi-icu, get_pomo, and treetop. 23 24require 'ffi-icu' 25require 'get_pomo' 26require 'treetop' 27require 'fileutils' 28 29MAX_LINE_WIDTH = 350 30DEFAULT_KERNING = 2 31LANGUAGE = ARGV[0] 32 33CFG_FILE = "data/dialog_font.#{LANGUAGE}.cfg" 34CFG_FILE.replace 'data/dialog_font.cfg' unless File.exist? CFG_FILE 35PO_FILE = "po/#{LANGUAGE}.po" 36 37unless File.exist? PO_FILE 38 abort "#{PO_FILE} does not exist" 39end 40 41Treetop.load 'utils/fml_font_cfg.treetop' 42 43parser = FrogattoFontCfgParser.new 44result = parser.parse(File.read(CFG_FILE)) 45unless result 46 puts parser.failure_reason 47 abort "Failed to parse #{CFG_FILE}" 48end 49CHARACTER_WIDTHS = result.character_widths 50KERNING = result.attributes.values['kerning'] || DEFAULT_KERNING 51 52def word_wrap(text) 53 line_breaker = ICU::BreakIterator.new(:line, LANGUAGE) 54 line_breaker.text = text 55 segments = line_breaker.each_cons(2).to_a 56 lines = [] 57 until segments.empty? 58 line = '' 59 line_width = 0 60 segments = segments.drop_while do |from, to| 61 segment = text[from...to] 62 segment_width = segment.chars.inject(0) do |total, character| 63 character_width = CHARACTER_WIDTHS[character] 64 unless character_width 65 abort "No glyph defined for #{character}, used in msgstr '#{text}'. If this language uses generated glyphs, try 'rake #{LANGUAGE}'" 66 end 67 total + character_width + KERNING 68 end 69 line_width += segment_width 70 line_width <= MAX_LINE_WIDTH && line << segment 71 end 72 lines << line.strip 73 end 74 lines.join "\\n" 75end 76 77po = GetPomo::PoFile.new 78po.add_translations_from_text(File.read(PO_FILE)) 79po.translations.each do |translation| 80 unless translation.msgid.empty? || 81 translation.msgstr.empty? || 82 translation.comment =~ /METADATA|CHANGELOG|titlescreen/ || 83 translation.msgstr =~ /[{}]/ || 84 translation.msgstr =~ /\\n/ && translation.comment !~ /automatically word wrapped/ 85 wrapped = word_wrap(translation.msgstr.gsub('\"', '"')).gsub('"', '\"') 86 if wrapped != translation.msgstr 87 puts "Word-wrapped:\n#{translation.msgid}\n#{wrapped}" 88 translation.comment += "automatically word-wrapped" 89 translation.msgstr = wrapped 90 end 91 end 92end 93File.open(PO_FILE, 'w') {|file| file.write po.to_text} 94 95system "msgmerge #{PO_FILE} po/frogatto.pot -o #{PO_FILE}.part" 96FileUtils.mv "#{PO_FILE}.part", PO_FILE 97 98