Class: Locallingo::StateStore

Inherits:
Object
  • Object
show all
Defined in:
lib/locallingo/state_store.rb

Overview

Reads and writes the source-hash drift state under state_dir.

State is split into one JSON file per top-level namespace and locale (accounts.de.json, ...) so diffs stay small and reviewable. Each entry records the source hash a key was translated from, so a later source change marks the translation outdated. Optionally a target_hash and manual flag are tracked so hand-edited target values can be protected from overwrites.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(state_dir) ⇒ StateStore

Returns a new instance of StateStore.



18
19
20
21
# File 'lib/locallingo/state_store.rb', line 18

def initialize(state_dir)
  @state_dir = state_dir
  FileUtils.mkdir_p(@state_dir)
end

Instance Attribute Details

#state_dirObject (readonly)

Returns the value of attribute state_dir.



16
17
18
# File 'lib/locallingo/state_store.rb', line 16

def state_dir
  @state_dir
end

Class Method Details

.hash(text) ⇒ Object

CRC32 hash — fast and compact (8 hex chars).



24
25
26
# File 'lib/locallingo/state_store.rb', line 24

def self.hash(text)
  format("%08x", Zlib.crc32(text.to_s))
end

Instance Method Details

#hash(text) ⇒ Object



28
# File 'lib/locallingo/state_store.rb', line 28

def hash(text) = self.class.hash(text)

#load(locale) ⇒ Object

Load the combined state for a locale (merged across its namespace files).



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/locallingo/state_store.rb', line 31

def load(locale)
  combined = {}
  Dir.glob(File.join(state_dir, "*.#{locale}.json")).each do |file|
    combined.merge!(JSON.parse(File.read(file)))
  end
  combined
rescue JSON::ParserError => e
  raise Error,
        "Corrupted state file: #{e.message}\n" \
        "This would cause state loss. Fix the JSON manually or restore from git."
end

#save(locale, locale_state) ⇒ Object

Save a locale's state, split back into per-namespace files. Files whose content is unchanged are left untouched so unrelated namespaces never churn in diffs. Namespace files that no longer have keys are removed.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/locallingo/state_store.rb', line 46

def save(locale, locale_state)
  by_namespace = locale_state.each_with_object({}) do |(key, value), groups|
    namespace = key.split(".").first
    (groups[namespace] ||= {})[key] = value
  end

  by_namespace.each do |namespace, keys|
    state_file = File.join(state_dir, "#{namespace}.#{locale}.json")
    content = JSON.pretty_generate(keys.sort.to_h)
    next if File.exist?(state_file) && File.read(state_file) == content

    File.write(state_file, content)
  end

  Dir.glob(File.join(state_dir, "*.#{locale}.json")).each do |file|
    namespace = File.basename(file).delete_suffix(".#{locale}.json")
    File.delete(file) unless by_namespace.key?(namespace)
  end
end