1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
# Copyright (C) 2020 Sutou Kouhei <kou@clear-code.com>
#
# License: Ruby's or LGPL
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require "English"
require "cgi"
require "strscan"
require "gettext/po_entry"
module GetText
class GtkBuilderUIDefinitionsParser
@config = {
:extnames => [".ui"]
}
class << self
# Sets some preferences to parse GtkBuilder UI definitions files.
# * config: a Hash of the config. It can takes some values below:
# * :extnames: An Array of target files extension. Default is [".ui"].
def init(config)
config.each do |k, v|
@config[k] = v
end
end
def target?(file) # :nodoc:
@config[:extnames].each do |extname|
return true if File.extname(file) == extname
end
false
end
def parse(path, options={})
parser = new(path, options)
parser.parse
end
end
TARGET1 = /<property.*translatable="yes">(.*)/
TARGET2 = /(.*)<\/property>/
def initialize(path, options={})
@path = path
@options = options
end
def parse # :nodoc:
File.open(@path) do |file|
po = []
start_line_no = nil
property = nil
file.each_line do |line|
case line
when /<property/
property = $POSTMATCH
start_line_no = file.lineno
if /<\/property>/ =~ property
property << $PREMATCH
add_po_entry(po, property, start_line_no)
property = nil
end
when /<\/property>/
property << $PREMATCH
add_po_entry(po, property, start_line_no)
property = nil
else
property << line if property
end
end
po
end
end
private
def add_po_entry(po, property, line_no)
raw_attributes, raw_data_and_close_tag = property.split(">", 2)
raw_data, _close_tag = raw_data_and_close_tag.split("<", 2)
return if raw_data.empty?
attributes = parse_attributes(raw_attributes)
return unless attributes["translatable"] == "yes"
data = CGI.unescapeHTML(raw_data)
context = attributes["context"]
if context
po_entry = POEntry.new(:msgctxt)
po_entry.msgctxt = context
else
po_entry = POEntry.new(:normal)
end
po_entry.msgid = data
po_entry.references << "#{@path}:#{line_no}"
po << po_entry
end
def parse_attributes(raw_attributes)
scanner = StringScanner.new(raw_attributes)
attributes = {}
loop do
scanner.scan(/\s*/m)
break if scanner.eos?
name = scanner.scan(/[^=]+/)
break if name.nil?
break unless scanner.scan(/=/)
quote = scanner.scan(/["']/)
break if quote.nil?
value = scanner.scan(/[^#{Regexp.escape(quote)}]+/m)
break if value.nil?
break unless scanner.scan(/#{Regexp.escape(quote)}/)
attributes[name] = CGI.unescapeHTML(value)
end
attributes
end
end
end
|