Class: I18nContextGenerator::XcstringsDocument

Inherits:
Object
  • Object
show all
Defined in:
lib/i18n_context_generator/xcstrings_document.rb

Overview

Structural index for an Apple string catalog that retains byte offsets in the original JSON. It lets write-back edit only owned comment values and lets diff handling map revision-specific line numbers without reformatting.

Defined Under Namespace

Classes: Member

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content, path:) ⇒ XcstringsDocument

Returns a new instance of XcstringsDocument.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/i18n_context_generator/xcstrings_document.rb', line 34

def initialize(content, path:)
  @content = content
  @path = path
  @catalog = Oj.load(content, mode: :strict)
  @line_starts = [0]
  content.each_byte.with_index { |byte, index| @line_starts << (index + 1) if byte == BYTE[:newline] }
  @root_members = object_members(skip_whitespace(0))
  strings_member = @root_members.find { |member| member.key == 'strings' }
  strings_object = strings_member && byte_at(strings_member.value_start) == BYTE[:open_object]
  raise TypeError, 'strings must be a mapping' unless strings_object

  @strings_member = strings_member
  @entry_members = object_members(strings_member.value_start)
  @entries_by_key = @entry_members.to_h { |member| [member.key, member] }
rescue Oj::ParseError, TypeError => e
  raise Error, "Failed to parse Apple string catalog #{path}: #{e.message}"
end

Instance Attribute Details

#catalogObject (readonly)

Returns the value of attribute catalog.



32
33
34
# File 'lib/i18n_context_generator/xcstrings_document.rb', line 32

def catalog
  @catalog
end

Instance Method Details

#line_indexObject



52
53
54
55
56
57
58
# File 'lib/i18n_context_generator/xcstrings_document.rb', line 52

def line_index
  @entry_members.each_with_object({}) do |member, index|
    start_line = line_number(member.key_start)
    end_line = line_number(member.value_end - 1)
    (start_line..end_line).each { |line| index[line] = member.key }
  end
end

#with_comments(comments_by_key) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/i18n_context_generator/xcstrings_document.rb', line 60

def with_comments(comments_by_key)
  edits = comments_by_key.filter_map do |key, comment|
    entry_member = @entries_by_key[key]
    next unless entry_member && byte_at(entry_member.value_start) == BYTE[:open_object]
    next if @catalog.dig('strings', key, 'comment') == comment

    comment_edit(entry_member, comment)
  end
  return @content if edits.empty?

  original_encoding = @content.encoding
  rendered = @content.b
  edits.sort_by(&:first).reverse_each do |start_offset, end_offset, replacement|
    rendered[start_offset...end_offset] = replacement.b
  end
  rendered.force_encoding(original_encoding)
end