FastGettext

repository·master·Indexed 19 days ago

https://github.com/grosser/fast_gettext

A high-performance, thread-safe internationalization (i18n) library for Ruby. It supports multiple translation backends including .mo, .po, .yml files and databases. FastGettext provides features for pluralization, contextual translations, multi-domain support, and the ability to chain or merge multiple translation repositories for increased flexibility.

Tokens
6.5K
Snippets
29
Records
31
Agent score
64%

What's inside fast_gettext

  1. Use translation chains and merge repositories

    master

    You can combine multiple repositories to search for translations in sequence.

    • Chains (type: :chain): Iterates through the list of repositories. If the first cannot find a translation, it asks the next.
    • Merge (type: :merge): Similar to chains but optimizes speed by selecting and storing the first translation found at load time. Note: You must call domain.reload if the locale changes.
    • Loggers: You can add a logger to a chain to track missing translations. A lambda responding to call can be used as a callback.
    # Chain
    repos = [
      FastGettext::TranslationRepository.build('new', path: '....'),
      FastGettext::TranslationRepository.build('old', path: '....')
    ]
    FastGettext.add_text_domain 'combined', type: :chain, chain: repos
    
    # Merge
    domain = FastGettext.add_text_domain 'combined', type: :merge, chain: repos
    # If locale changes:
    FastGettext.locale = 'de'
    domain.reload
    
    # Logger
    repos = [
      FastGettext::TranslationRepository.build('app', path: '....'),
      FastGettext::TranslationRepository.build('logger', type: :logger, callback: ->(key_or_array_of_ids) { puts "Missing: #{key_or_array_of_ids}" }),
    ]
    FastGettext.add_text_domain 'combined', type: :chain, chain: repos
  2. Use block defaults for missing translations

    master

    All translation methods support a block default. If a translation is not found, the block is executed and its return value is used instead of the original key.

    _('not-found') { "alternative default" }
    
    # Useful for complex logic or logging
    _('terms-and-conditions') {
      load_terms_and_conditions
      request_terms_and_conditions_translation_from_legal
    }
  3. Add a translation repository

    master

    You must register a text domain and specify where the translations are stored using FastGettext.add_text_domain. FastGettext supports several backend types:

    • .mo files (default): Traditional GetText compiled files.
    • .po files: Human-readable GetText files. Use type: :po. You can pass ignore_fuzzy: true to skip fuzzy translations or report_warning: false to hide warnings about obsolete/fuzzy translations.
    • .yml files: Uses I18n syntax/indentation. Use type: :yaml. Note that a single locale can be segmented across multiple YAML files, provided they are named with a {locale}.yml suffix (e.g., de.yml).
    • Database: Scalable for many locales. Requires loading the DB repository models and specifying a model class.
    # MO files
    FastGettext.add_text_domain('my_app', path: 'locale')
    
    # PO files
    FastGettext.add_text_domain('my_app', path: 'locale', type: :po)
    
    # YAML files
    FastGettext.add_text_domain('my_app', path: 'config/locales', type: :yaml)
    
    # Database (ActiveRecord example)
    require "fast_gettext/translation_repository/db"
    FastGettext::TranslationRepository::Db.require_models
    FastGettext.add_text_domain('my_app', type: :db, model: TranslationKey)
  4. Configure text domain and locale

    master

    In multi-threaded environments (like Rails), you must set the text domain and locale within every thread (e.g., in an ApplicationController).

    • FastGettext.text_domain: The name of the domain to use.
    • FastGettext.available_locales: An optional array of allowed locales.
    • FastGettext.locale: The current active locale.
    FastGettext.text_domain = 'my_app'
    FastGettext.available_locales = ['de', 'en', 'fr']
    FastGettext.locale = 'de'
  5. Use dot notation for nested YAML translations

    master

    The Fastgettext::TranslationRepository::Yaml class automatically flattens nested YAML structures into a single-level hash using dot notation. This allows you to access deeply nested translation keys as a single string key.

    For example, a YAML structure like:

    en:
      errors:
        messages:
          not_found: "Not Found"

    will be accessible via the key errors.messages.not_found.

  6. Define pluralisation rules in YAML

    master

    The YAML repository supports custom pluralisation rules. You can define a pluralisation_rule key within your YAML file. The value should be a string containing Ruby code that can be evaluated to return a rule.

    When a rule is defined, the repository provides a pluralisation_rule method that returns a lambda. This lambda accepts an integer n (the count) and evaluates the rule string to determine the correct plural form.

    Additionally, you can use the plural method to retrieve the standard set of plural forms (one, other, plural2, plural3) for a given key using dot notation.

    # Example YAML content with a pluralisation rule
    en:
      pluralisation_rule: "n == 1 ? 'one' : 'other'"
      items:
        one: "one item"
        other: "%{count} items"
  7. Use FastGettext::TranslationRepository::Merge to combine multiple translation sources

    master

    The FastGettext::TranslationRepository::Merge class allows you to aggregate translations from multiple repositories into a single unified repository. This is useful when you want to treat multiple translation sources as one, rather than searching through multiple domains.

    Key behaviors:

    • Merging Logic: When loading repositories, the data is merged such that existing keys in @data are updated by the new repository's translations (via repo.all_translations.merge(@data)).
    • Reloading: Because it aggregates data, you must call #reload if the current locale changes to ensure the merged hash is correctly rebuilt.
    • Pluralization: It searches through the underlying repositories sequentially to find the first available pluralisation_rule or plural translation.
    # Example of initializing a merged repository with a chain of other repositories
    merged_repo = FastGettext::TranslationRepository::Merge.new('merged_name', chain: [repo1, repo2])
    
    # Accessing translations
    translation = merged_repo[:some_key]
    
    # If the locale changes, you must reload the merged repository
    merged_repo.reload
  8. Use basic translation methods

    master

    To use the translation methods, include FastGettext::Translation in your class. To enable the shorthand _() and n_() methods, include FastGettext::TranslationAliased.

    • _('string') or gettext('string'): Basic translation. Returns the msgid if no translation is found.
    • n_('singular', 'plural', count) or ngettext(...): Pluralization based on a count.
    • p_('context', 'string') or pgettext(...): Translation with context.
    • s_('context|string') or sgettext(...): Translation with a namespace.
    • pn_('context', 'singular', 'plural', count'): Context-aware pluralization.
    • sn_('context|singular', 'plural', count'): Namespace-aware pluralization.
    • N_('string'): Marks a string for discovery by the parser (static analysis).
    # Basic
    _('Car')
    
    # Pluralization
    n_('Car', 'Cars', 1)
    
    # Context
    p_('File', 'Open')
    
    # Namespace
    s_('File|Open')
    
    # Context-aware plural
    pn_('Fruit', 'Apple', 'Apples', 3)
    
    # Parser discovery
    N_("active")
  9. Configure custom pluralisation rules

    master

    Plurals are selected by index. You can define custom rules via Ruby or via .po files.

    # Via Ruby
    FastGettext.pluralisation_rule = ->(count){ count > 5 ? 1 : (count > 2 ? 0 : 2)}
    
    # Via .po file
    # Plural-Forms: nplurals=2; plural=n==2?3:4;
  10. Use Multi-domain translation methods

    master

    If you have multiple text domains, include FastGettext::TranslationMultidomain to access specialized methods.

    • d_(domain, string): Finds string in a specific domain.
    • D_(string): Finds string in any domain (returns a random one if multiple exist).
    • dn_(domain, singular, plural, count): Pluralization within a specific domain.
    • Dnp_(domain, context, string, plural, count): Pluralization with context in a specific domain.
    • Dp_(domain, context, key): Contextual translation in a specific domain.
    • Ds_(domain, context|key): Namespace translation in a specific domain.
    extend FastGettext::TranslationMultidomain
    
    d_("domainname", "string")
    Dn_("domainname", "strings", 1)
    Dp_("domainname", "context", "key")
    Ds_("domainname", "context|key")
    D_("string") # Search all domains
  11. Configure the YAML translation repository

    master

    The Fastgettext::TranslationRepository::Yaml class is used to load translations from YAML files. By default, it searches for .yml files in the config/locales directory.

    To specify a different directory, pass the :path option during initialization.

    File Naming Convention: To ensure locales are correctly identified, files must follow a specific naming pattern where the locale is the last dot-separated part of the filename before the extension.

    • qq.yml (where qq is the locale)
    • foo.qq.yml (where qq is the locale)

    Example: If you have a locale named en, your files should be named en.yml or messages.en.yml.

    # Example of initializing with a custom path
    repo = Fastgettext::TranslationRepository::Yaml.new('my_repo', path: 'locales/custom')