Code Monkey home page Code Monkey logo

lokalise_rails's Introduction

LokaliseRails

Gem CI Coverage Status Maintainability Downloads total

This gem provides Lokalise integration for Ruby on Rails and allows to exchange translation files easily. It relies on lokalise_manager which perform the actual import/export and can be used to run this task in any Ruby script.

If you would like to know how this gem was built, check out the "How to create a Ruby gem" series at Lokalise blog.

Getting started

Requirements

This gem requires Ruby 3.0+ and Rails 5.1+. It might work with older versions of Rails though. You will also need to setup a Lokalise account and create a translation project. Finally, you will need to generate a read/write API token at your Lokalise profile.

Alternatively, you can utilize a token obtained via OAuth 2 flow. When using such a token, you'll have to set :use_oauth2_token option to true (please check options docs to learn more).

Installation

Add the gem to your Gemfile (it can be added to the development group if you're not planning to import/export translations in production):

gem 'lokalise_rails'

and run:

bundle install
rails g lokalise_rails:install

The latter command will generate a new config file config/lokalise_rails.rb looking like this:

LokaliseRails::GlobalConfig.config do |c|
  c.api_token = ENV['LOKALISE_API_TOKEN']
  c.project_id = ENV['LOKALISE_PROJECT_ID']

  # ...other options
end

You have to provide api_token and project_id to proceed. project_id can be found in your Lokalise project settings.

Other options can be customized as well but they have sensible defaults. To learn about all the available options please check lokalise_manager docs. The generated config file also contains some examples to help you get started.

Importing translations from Lokalise

To import translations from the specified Lokalise project to your Rails app, run the following command:

rails lokalise_rails:import

Please note that any duplicating files inside the locales directory (or any other directory that you've specified in the options) will be overwritten! You can enable safe mode to check whether the folder is empty or not.

Exporting translations to Lokalise

To export translations from your Rails app to the specified Lokalise project, run the following command:

rails lokalise_rails:export

Running tasks programmatically

You can also run the import and export tasks programmatically from your code. To achieve that, please check the lokalise_manager gem which lokalise_rails relies on.

For example, you can use the following approach:

# This line is actually not required. Include it if you would like to use your global settings:
require "#{Rails.root}/config/lokalise_rails.rb"

importer = LokaliseManager.importer({api_token: '1234abc', project_id: '123.abc'}, LokaliseRails::GlobalConfig)

# OR

exporter = LokaliseManager.exporter({api_token: '1234abc', project_id: '123.abc'}, LokaliseRails::GlobalConfig)

The first argument passed to importer or exporter is the hash containing per-client options. This is an optional argument and you can simply pass an empty hash if you don't want to override any global settings.

The second argument is the name of your global config which is usually stored inside the lokalise_rails.rb file (however, you can subclass this global config and even adjust the defaults as explained here). If you would like to use LokaliseRails global defaults, then you must pass this class to the clients. If you don't do this, then LokaliseManager defaults will be used instead. The only difference is the location where translation files are stored. For LokaliseManager we use ./locales directory, whereas for LokaliseRails the directory is ./config/locales.

However, you can also provide the translation files folder on per-client basis, for instance:

importer = LokaliseManager.importer api_token: '1234abc', project_id: '123.abc', locales_path: "#{Rails.root}/config/locales"

After the client is instantiated, you can run the corresponding task:

importer.import!

# OR 

exporter.export!

Example: Multiple translation paths

Creating custom import/export script can come in really handy if you have a non-standard setup, for instance, your translation files are stored in multiple directories (not only in the default ./config/locales. To overcome this problem, create a custom Rake task and provide as many importers/exporters as needed:

require 'rake'
require 'lokalise_rails'
require "#{LokaliseRails::Utils.root}/config/lokalise_rails"

namespace :lokalise_custom do
  task :export do
    # importing from the default directory (./config/locales/)
    exporter = LokaliseManager.exporter({}, LokaliseRails::GlobalConfig)
    exporter.export!

    # importing from the custom directory
    exporter = LokaliseManager.exporter({locales_path: "#{Rails.root}/config/custom_locales"}, LokaliseRails::GlobalConfig)
    exporter.export!
  rescue StandardError => e
    abort e.inspect
  end
end

Configuration

Options are specified in the config/lokalise_rails.rb file.

Here's an example:

LokaliseRails::GlobalConfig.config do |c|
  # These are mandatory options that you must set before running rake tasks:
  c.api_token = ENV['LOKALISE_API_TOKEN']
  c.project_id = ENV['LOKALISE_PROJECT_ID']

  # Provide a custom path to the directory with your translation files:
  # c.locales_path = "#{Rails.root}/config/locales"

  # Provide a Lokalise project branch to use:
  c.branch = 'develop'

  # Provide request timeouts for the Lokalise API client:
  c.timeouts = {open_timeout: 5, timeout: 5}

  # Provide maximum number of retries for file exporting:
  c.max_retries_export = 5

  # Provide maximum number of retries for file importing:
  c.max_retries_import = 5

  # Import options have the following defaults:
  # c.import_opts = {
  #   format: 'ruby_yaml',
  #   placeholder_format: :icu,
  #   yaml_include_root: true,
  #   original_filenames: true,
  #   directory_prefix: '',
  #   indentation: '2sp'
  # }

  # Safe mode for imports is disabled by default:
  # c.import_safe_mode = false

  # Additional export options (only filename, contents, and lang_iso params are provided by default)
  # c.export_opts = {}

  # Provide additional file exclusion criteria for exports (by default, any file with the proper extension will be exported)
  # c.skip_file_export = ->(file) { file.split[1].to_s.include?('fr') }

  # Set the options below if you would like to work with format other than YAML
  ## Regular expression to use when choosing the files to extract from the downloaded archive and upload to Lokalise
  ## c.file_ext_regexp = /\.ya?ml\z/i

  ## Load translations data and make sure they are valid:
  ## c.translations_loader = ->(raw_data) { YAML.safe_load raw_data }

  ## Convert translations data to a proper format:
  ## c.translations_converter = ->(raw_data) { YAML.dump(raw_data).gsub(/\\\\n/, '\n') }

  ## Infer language ISO code for the translation file:
  ## c.lang_iso_inferer = ->(data, _path) { YAML.safe_load(data)&.keys&.first }
end

Running tests

  1. Copypaste .env.example file as .env. Put your Lokalise API token and project ID inside. The .env file is excluded from version control so your data is safe. All in all, we use stubbed requests, so the actual API requests won't be sent. However, providing at least some values is required.
  2. Run rspec .. Observe test results and code coverage.

License

Copyright (c) Ilya Krukowski. License type is MIT.

lokalise_rails's People

Contributors

bodrovis avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

lokalise_rails's Issues

Cannot export to Ruby on Rails project as default placeholders are wrong

Describe the bug
Hello, the default format: :ruby_yaml and placeholder_format: :icu does not work with a Ruby on Rails project with the default i18n setup using the rails-i18n gem.

Ruby on Rails expects placeholders to be %{my_placeholder} but this gem exports as {my_placeholder} when using type :icu.

I cannot get any combination of format/placeholder_format for the file export to work with this gem and a Ruby on Rails project. Can you confirm how to use this gem?

To Reproduce

  1. Export a file from Lokalise with default parameters
  # Import options have the following defaults:
  # c.import_opts = {
  #   format: 'yaml',
  #   placeholder_format: :icu,
  #   yaml_include_root: true,
  #   original_filenames: true,
  #   directory_prefix: '',
  #   indentation: '2sp'
  # }
  1. Use this file in the default config/locales folder of a Ruby on Rails project
  2. You will see that placeholders show up as {my_placeholder} when translating a string, instead of using the replaced variable. This is due to Rails expecting %{my_placeholder}

Expected behavior
We expect that this gem should export as %{my_placeholder}, the only format supported by Ruby on Rails rails-i18n gem.

Your environment:

  • Ruby version '2.7.5'
  • Rails version '6.0.5'

Additional context
See how placeholders work in i18n interpolation documentation
https://guides.rubyonrails.org/i18n.html#passing-variables-to-translations

Checked with your support team to log a ticket, they suggested to go ahead. Thanks!

Line breaks in strings containing html get double escaped on import

When importing translation strings containing html tags and line breaks (\n), the line breaks get double escaped (\\n instead of \n) when using rails lokalise_rails:import.

How To Reproduce

  • Create a rails app, add the lokalise_rails gem and put the following content in locales/en.yml:
en:
  hello_html: "<h1>\nhello world\n</h1>\n"
  • Create a fully standard project in lokalise.
  • In config/lokalise_rails.rb, only add the project_id and personal key and leave everything else commented
  • Run rails lokalise_rails:export followed by rails lokalise_rails:import

This results in the en.yml file in the rails project looking like this:

en:
  hello_html: "<h1>\\nhello world\\n</h1>\\n"

As a result, rails renders literal '\n' text rather than line breaks in the page source.

Note: when manually downloading the file directly from the lokalise portal the line breaks are correctly escaped.

Expected behavior
The exported yaml files should be the same as when downloading manually from the lokalise portal.

Your environment:

  • Mac OS 11.6.6
  • ruby 2.7.5p203

Installing the gem for only development group

The feature I'd like is...
Currently, the instructions tell you to put the gem inside the :production group in Gemfile.

In most cases, I imagine this might not be necessary and might be just increasing the production bundle size without serving a purpose in the production build.

Would it be possible to have the gem in :development group by default?

Additional context
I've achieved this locally by loading the config conditionally:

# frozen_string_literal: true
# config/lokalise_rails.rb

if defined?(LokaliseRails::GlobalConfig)
  LokaliseRails::GlobalConfig.config do |c|
    # These are mandatory options that you must set before running rake tasks:
    c.api_token = ENV.fetch("LOKALISE_API_TOKEN", nil)
    c.project_id = ENV.fetch("LOKALISE_PROJECT_ID", nil)
  end
end

and adding the gem to that group. But I think this should perhaps be a sensible default.

Export doesn't return error status when failing

Describe the bug
export rake doesn't exit with an error status code when it fails.

To Reproduce
This can be reproduce by having an invalid yml file and trying to export it usingbundle exec rails lokalise_rails:export.

Expected behavior
We expect bundle exec rails lokalise_rails:export to return 1 when it fails to export files.

Your environment:

  • Ruby 2.7.1

lokalise_rails:import fails in v4.0.0

Running of rails lokalise_rails:import raises
#<NoMethodError: undefined method 'filter' for #<Array:...>>

The reason is usage of Array#filter here. Array#filter was added in Ruby 2.6, while gemspec of lokalise_manager v2.1.0 is meant to work on Ruby 2.5.0

Old version of lokalise_rails is installed / Import not working

Hi there!

I tried to install lokalise_rails 5.2.0 but this is not working due to this error:

Could not find compatible versions

    Because faraday_middleware < 0.1.4 depends on faraday ~> 0.4.5
      and faraday_middleware >= 0.1.4, < 0.1.7 depends on faraday ~> 0.5.0,
      faraday_middleware < 0.1.7 requires faraday ~> 0.4.5 OR ~> 0.5.0.
    And because faraday_middleware >= 0.1.7, < 0.2.2 depends on faraday ~> 0.5.1,
      faraday_middleware < 0.2.2 requires faraday ~> 0.4.5 OR >= 0.5.0, < 0.6.A.
    And because faraday_middleware >= 0.2.2, < 0.3.0 depends on faraday ~> 0.5.2
      and faraday_middleware >= 0.3.0, < 0.3.2 depends on faraday ~> 0.5.3,
      faraday_middleware < 0.3.2 requires faraday ~> 0.4.5 OR >= 0.5.0, < 0.6.A.
    And because faraday_middleware >= 0.3.2, < 0.6.0 depends on faraday ~> 0.5.4
      and faraday_middleware >= 0.6.0, < 0.7.0.rc1 depends on faraday ~> 0.6.0,
      faraday_middleware < 0.7.0.rc1 requires faraday ~> 0.4.5 OR >= 0.5.0, < 0.6.A OR ~> 0.6.0.
    And because faraday_middleware >= 0.7.0.rc1, < 0.8.0 depends on faraday ~> 0.7.3
      and faraday_middleware >= 0.8.0, < 0.9.1 depends on faraday >= 0.7.4, < 0.9,
      faraday_middleware < 0.9.1 requires faraday ~> 0.4.5 OR >= 0.5.0, < 0.6.A OR ~> 0.6.0 OR >= 0.7.3, < 0.9.
    And because faraday_middleware >= 0.9.1, < 0.10.1 depends on faraday >= 0.7.4, < 0.10
      and faraday_middleware >= 0.10.1, < 1.0.0.rc1 depends on faraday >= 0.7.4, < 1.0,
      faraday_middleware < 1.0.0.rc1 requires faraday ~> 0.4.5 OR >= 0.5.0, < 0.6.A OR ~> 0.6.0 OR >= 0.7.3, < 1.0.
(1) So, because faraday_middleware >= 1.0.0.rc1 depends on faraday ~> 1.0
      and ruby-lokalise-api >= 5.0.0 depends on faraday ~> 2.0,
      ruby-lokalise-api >= 5.0.0 cannot be used.

    Because lokalise_manager >= 3.0.0, < 3.3.0 depends on ruby-lokalise-api ~> 6.0
      and lokalise_rails >= 5.1.0 depends on lokalise_manager ~> 3.2,
      lokalise_rails >= 5.1.0 requires ruby-lokalise-api ~> 6.0 or lokalise_manager >= 3.3.0, < 4.A.
    And because lokalise_manager >= 3.3.0 depends on ruby-lokalise-api ~> 7,
      lokalise_rails >= 5.1.0 requires ruby-lokalise-api ~> 6.0 OR ~> 7.
    And because ruby-lokalise-api >= 5.0.0 cannot be used (1),
      lokalise_rails >= 5.1.0 cannot be used.
    So, because Gemfile depends on lokalise_rails ~> 5.2.0,
      version solving has failed.

If I use the default version (4.0.0, if you don't specify a version), the following error is shown during import:

#<Psych::DisallowedClass: Tried to load unspecified class: Error while trying to upload /Users/daniel/projects/extrusion-os/config/locales/en.yml: Tried to load unspecified class: Symbol>

Basic integration not working

Describe the bug

Hi there,
We are currently testing the lokalise integration as a potential solution to translate our app and came across the following issue, wondering if you might be able to help.

ArgumentError when translating the following file:

en_GB:
  accounts:
    show:
      heading: Your Account
    update:
      failure: Unable to update your account, check the issues below
      success: Successfully updated your account

To Reproduce
Follow this guide to set up the gem and attempt to export the above using the rake task.

Expected behavior
No error

Your environment:
macOS 14.0
Ruby 3.1.4

Additional context
Also had to rename the top-level key from en: to en_GB: which is in itself not something I want to have to do but en alone caused another error: RubyLokaliseApi::Error::BadRequest: Error while trying to upload [REDACTED]/en.yml: Invalid `lang_iso` parameter

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.