module Mova::Scope

Translation keys are usually organized in a tree, where each nesting level corresponds to a specific part of your application. Such hierarchical organization allows to reuse the keys and keep their names relatively short.

Full path to a key forms a scope. Think of a scope as a namespace.

# here we have an example YAML file with "blank" keys within different scopes
activemodel:
  errors:
    blank: Can't be blank
    message:
      blank: Please provide a message

Since Mova is designed to work with any key-value storage, we need to store a key with its own full scope and a locale. We use dot-separated strings as it’s a common format in Ruby community.

"en.activemodel.errors.blank"
"en.activemodel.errors.message.blank"

@note In YAML (and other storages that map to a hash) you can’t store a value

for a nesting level itself.
  errors: !can't have translation here
    blank: Please enter a value
Other key-value storages usually don't have such limitation, however, it's better
to not introduce incompatibles in this area.

@since 0.1.0

Constants

SEPARATOR

Public Instance Methods

cross_join(locales, keys) click to toggle source

Combines each locale with all keys.

@return [Array<String>] @param locales [Array<String, Symbol>] @param keys [Array<String, Symbol>]

@example

Scope.cross_join([:de, :en], [:hello, :hi]) #=>
  ["de.hello", "de.hi", "en.hello", "en.hi"]
# File lib/mova/scope.rb, line 88
def cross_join(locales, keys)
  locales.map do |locale|
    keys.map { |key| join(locale, key) }
  end.flatten
end
flatten(translations, current_scope = nil) click to toggle source

Recurrently flattens hash by converting its keys to fully scoped ones.

@return [Hash{String => String}] @param translations [Hash{String/Symbol => String/Hash}] with multiple

roots allowed

@param current_scope for internal use

@example

Scope.flatten(en: {common: {hello: "hi"}}, de: {hello: "Hallo"}) #=>
  {"en.common.hello" => "hi", "de.hello" => "Hallo"}
# File lib/mova/scope.rb, line 68
def flatten(translations, current_scope = nil)
  translations.each_with_object({}) do |(key, value), memo|
    scope = current_scope ? join(current_scope, key) : key.to_s
    if value.is_a?(Hash)
      memo.merge!(flatten(value, scope))
    else
      memo[scope] = value
    end
  end
end
join(*parts) click to toggle source

Makes a new scope from given parts.

@return [String] @param parts [Array<String, Symbol>, *Array<String, Symbol>]

@example

Scope.join("hello", "world") #=> "hello.world"
Scope.join([:hello, "world"]) #=> "hello.world"
# File lib/mova/scope.rb, line 43
def join(*parts)
  parts.join(SEPARATOR)
end
split(scope) click to toggle source

Split a scope into parts.

@return [Array<String>] @param scope [String]

@example

Scope.split("hello.world") #=> ["hello", "world"]
# File lib/mova/scope.rb, line 54
def split(scope)
  scope.split(SEPARATOR)
end