Class: Kotoshu::Cache::LanguageCache
- Defined in:
- lib/kotoshu/cache/language_cache.rb
Overview
Language cache for dynamic dictionary and grammar rule downloads.
Manages per-language dictionary and grammar rule downloads from a remote
repository. Resources are cached locally in $XDG_CACHE_HOME/kotoshu/languages/{code}/
with metadata for versioning and expiration.
Extends BaseCache for common download, metadata, and validation logic.
Constant Summary collapse
- RESOURCE_TYPES =
Supported resource types
%w[spelling grammar frequency].freeze
- AVAILABLE_LANGUAGES =
Available languages (plan 107): every language staged in the dictionaries manifest, vendored offline-safe by Cache::StagedLanguages and refreshed by
rake kotoshu:staged_languages:sync. Two tiers:- full feature — a language module under Kotoshu::Languages (registered keyboard + verified specimens); see full_feature_languages;
- basic — manifest-present but module-less: the script fallback tokenizer (Language::Script) and the generic keyboard default still serve setup/check/suggest. Local files come via setup --aff/--dic instead.
StagedLanguages::CODES
Instance Attribute Summary
Attributes inherited from BaseCache
#cache_path, #cache_ttl, #github_url, #max_cache_size, #source_registry, #url_base
Class Method Summary collapse
-
.full_feature_languages ⇒ Array<String>
Languages on the full-feature tier: staged in the manifest AND wired as a gem module (Kotoshu::Languages) — registered keyboard layout plus engine-verified specimens.
Instance Method Summary collapse
-
#available_languages ⇒ Array<String>
Get list of available languages.
-
#cache_size ⇒ Integer
Get cache size in bytes (override for language-specific tracking).
-
#cached_resources ⇒ Array<String>
List all cached resources.
-
#frequency_available?(language_code) ⇒ Boolean
Check if frequency data is available for a language.
-
#get_dictionary(language, force_download: false) ⇒ Hash
Alias for get_spelling for backward compatibility.
-
#get_grammar(language, force_download: false) ⇒ Hash
Get or download grammar rules for a language.
-
#get_spelling(language, force_download: false) ⇒ Hash
Get or download spelling dictionary for a language.
-
#install_local(language, aff:, dic:, force: false) ⇒ Hash
Install a spelling dictionary from local files (no download).
-
#language_info(language_code) ⇒ Hash
Get language metadata (word count, license, source).
-
#language_path(language, type) ⇒ String
Absolute on-disk path for a (language, resource_type) pair.
-
#load_cached(resource_id) ⇒ Object?
Load cached resource data (implements abstract method).
-
#metadata_path_for(resource_id) ⇒ String
Get metadata file path for a resource.
-
#resource_dir_for(resource_id) ⇒ String
Get resource directory path.
-
#resource_files_exist?(resource_id) ⇒ Boolean
Check if all resource files exist.
-
#supports_resource?(resource_id) ⇒ Boolean
Check if a resource type is supported.
Methods inherited from BaseCache
#available?, #cache_kind, #cached_data?, #clean, #clear, #clear_all, #download, #evict, #get, #initialize, #offline?, #read_metadata, #reset_stats, #stats
Constructor Details
This class inherits a constructor from Kotoshu::Cache::BaseCache
Class Method Details
.full_feature_languages ⇒ Array<String>
Languages on the full-feature tier: staged in the manifest AND wired as a gem module (Kotoshu::Languages) — registered keyboard layout plus engine-verified specimens. Everything else in #available_languages is the basic tier (plan 107).
137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/kotoshu/cache/language_cache.rb', line 137 def self.full_feature_languages Language::Registry.supported_codes .map { |code| code.split("-").first } .uniq .select { |base| AVAILABLE_LANGUAGES.include?(base) } .concat( # Script-keyed staged dictionaries (zh-Hans-CN resolves to # the zh-Hans wordlist) surface under their staged names. AVAILABLE_LANGUAGES.select { |code| code.include?("-") } ) .uniq .sort end |
Instance Method Details
#available_languages ⇒ Array<String>
Get list of available languages.
127 128 129 |
# File 'lib/kotoshu/cache/language_cache.rb', line 127 def available_languages AVAILABLE_LANGUAGES.dup end |
#cache_size ⇒ Integer
Get cache size in bytes (override for language-specific tracking).
183 184 185 186 187 188 189 |
# File 'lib/kotoshu/cache/language_cache.rb', line 183 def cache_size total = 0 Dir.glob(File.join(@cache_path, "languages", "**", "*.dic")).each do |path| total += File.size(path) if File.file?(path) end total end |
#cached_resources ⇒ Array<String>
List all cached resources.
194 195 196 197 198 199 200 |
# File 'lib/kotoshu/cache/language_cache.rb', line 194 def cached_resources Dir.glob(File.join(@cache_path, "languages", "**", "metadata.json")).map do |path| relative = Pathname.new(path).relative_path_from(Pathname.new(@cache_path)) parts = relative.to_s.split("/") "#{parts[1]}:#{parts[2]}" end.uniq end |
#frequency_available?(language_code) ⇒ Boolean
Check if frequency data is available for a language.
119 120 121 122 |
# File 'lib/kotoshu/cache/language_cache.rb', line 119 def frequency_available?(language_code) resource_id = "#{language_code}:frequency" available?(resource_id) end |
#get_dictionary(language, force_download: false) ⇒ Hash
Alias for get_spelling for backward compatibility.
100 101 102 |
# File 'lib/kotoshu/cache/language_cache.rb', line 100 def get_dictionary(language, force_download: false) get_spelling(language, force_download) end |
#get_grammar(language, force_download: false) ⇒ Hash
Get or download grammar rules for a language.
109 110 111 112 113 |
# File 'lib/kotoshu/cache/language_cache.rb', line 109 def get_grammar(language, force_download: false) resource_id = "#{language}:grammar" result = get(resource_id, force_download: force_download) result || download_grammar(language) end |
#get_spelling(language, force_download: false) ⇒ Hash
Get or download spelling dictionary for a language.
47 48 49 50 51 |
# File 'lib/kotoshu/cache/language_cache.rb', line 47 def get_spelling(language, force_download: false) resource_id = "#{language}:spelling" result = get(resource_id, force_download: force_download) result || download_spelling(language) end |
#install_local(language, aff:, dic:, force: false) ⇒ Hash
Install a spelling dictionary from local files (no download). Used by ResourceManager.setup_from_local when the user already has .aff/.dic files on disk. Symlinks the source files into the cache directory so subsequent cache lookups find them. Existing symlinks are replaced when force: true; existing real files raise ArgumentError unless force: true.
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 |
# File 'lib/kotoshu/cache/language_cache.rb', line 65 def install_local(language, aff:, dic:, force: false) require "fileutils" resource_id = "#{language}:spelling" lang_path = resource_dir_for(resource_id) FileUtils.mkdir_p(lang_path) target_aff = File.join(lang_path, "index.aff") target_dic = File.join(lang_path, "index.dic") if File.exist?(target_aff) || File.symlink?(target_aff) raise ArgumentError, "#{target_aff} already exists (use force: true to overwrite)" unless force File.unlink(target_aff) end if File.exist?(target_dic) || File.symlink?(target_dic) raise ArgumentError, "#{target_dic} already exists (use force: true to overwrite)" unless force File.unlink(target_dic) end File.symlink(File.(aff), target_aff) File.symlink(File.(dic), target_dic) ((resource_id), (language, "spelling", "local-source")) { aff_path: target_aff, dic_path: target_dic, source: :local } end |
#language_info(language_code) ⇒ Hash
Get language metadata (word count, license, source).
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/kotoshu/cache/language_cache.rb', line 169 def language_info(language_code) { "de" => { name: "German", word_count: 75_873, license: "GPL", source: "igerman98" }, "en" => { name: "English", word_count: 49_568, license: "LGPL/MPL/GPL", source: "SCOWL" }, "es" => { name: "Spanish", word_count: 57_344, license: "GPL", source: "LibreOffice" }, "fr" => { name: "French", word_count: 84_310, license: "MPL 2.0", source: "Grammalecte" }, "pt" => { name: "Portuguese", word_count: 312_368, license: "LGPLv3 + MPL", source: "VERO" }, "ru" => { name: "Russian", word_count: 146_269, license: "BSD-style", source: "Alexander Lebedev" } }[language_code] || { name: language_code.upcase, word_count: 0, license: "Unknown", source: "Unknown" } end |
#language_path(language, type) ⇒ String
Absolute on-disk path for a (language, resource_type) pair.
Composes cache_path/languages/{lang}/{type}. Use this rather
than reaching into cache_path from outside the cache — it
keeps the on-disk layout encapsulated and lets the layout
evolve without breaking callers.
161 162 163 |
# File 'lib/kotoshu/cache/language_cache.rb', line 161 def language_path(language, type) File.join(@cache_path, "languages", language, type) end |
#load_cached(resource_id) ⇒ Object?
Load cached resource data (implements abstract method).
Public — this is the cache-only reader BaseCache declares publicly; resolve paths use it to read without any download.
514 515 516 517 518 519 520 521 522 523 |
# File 'lib/kotoshu/cache/language_cache.rb', line 514 def load_cached(resource_id) parts = parse_resource_id(resource_id) return nil unless parts type = parts[1] = (resource_id) return nil unless load_cached_resource_by_type(resource_id, type, ) end |
#metadata_path_for(resource_id) ⇒ String
Get metadata file path for a resource.
529 530 531 532 533 |
# File 'lib/kotoshu/cache/language_cache.rb', line 529 def (resource_id) language = extract_language(resource_id) type = extract_type(resource_id) File.join(language_path(language, type), "metadata.json") end |
#resource_dir_for(resource_id) ⇒ String
Get resource directory path.
539 540 541 |
# File 'lib/kotoshu/cache/language_cache.rb', line 539 def resource_dir_for(resource_id) language_path(extract_language(resource_id), extract_type(resource_id)) end |
#resource_files_exist?(resource_id) ⇒ Boolean
Check if all resource files exist.
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
# File 'lib/kotoshu/cache/language_cache.rb', line 547 def resource_files_exist?(resource_id) type = extract_type(resource_id) return false unless type lang_path = resource_dir_for(resource_id) case type when "spelling" hunspell = File.exist?(File.join(lang_path, "index.aff")) && File.exist?(File.join(lang_path, "index.dic")) hunspell || File.exist?(File.join(lang_path, "words.txt")) when "grammar" File.exist?(File.join(lang_path, "rules.yaml")) when "frequency" File.exist?(File.join(lang_path, "frequency.json")) else false end end |
#supports_resource?(resource_id) ⇒ Boolean
Check if a resource type is supported.
206 207 208 209 210 211 212 |
# File 'lib/kotoshu/cache/language_cache.rb', line 206 def supports_resource?(resource_id) parts = resource_id.split(":") return false unless parts.size == 2 language, type = parts AVAILABLE_LANGUAGES.include?(language) && RESOURCE_TYPES.include?(type) end |