Lucky - i18n

Add Internationalization support to a Lucky Application
Icons/chart bar
Used 156 times
Created by
S Stephen Dolan

Usage
From within a Lucky application with the bloat gem installed, run:
bloat with https://railsbytes.com/script/VB0sAZ

Run this command in your Rails app directory in the terminal:

rails app:template LOCATION="https://railsbytes.com/script/VB0sAZ"
Template Source

Review the code before running this template on your machine.

def generate_user_language_database_migration(initial_language_code)
  say "Generating migration to add language to users", :yellow
  migration_output = run "lucky gen.migration AddLanguageToUser", capture: true
  migration_file = migration_output[/db\/migrations\/\S*_add_language_to_user\.cr/]

  say "Removing default content from generated migration", :yellow
  gsub_file migration_file, /^\s+#.*\n/, ""

  say "Modifying generated migration logic", :yellow
  insert_into_file migration_file, after: "def migrate\n" do
    <<-EOF
    alter table_for(User) do
      add language : String, default: "#{initial_language_code}"
    end
    EOF
  end

  say "Modifying generated migration rollback", :yellow
  insert_into_file migration_file, after: "def rollback\n" do
    <<-EOF
    alter table_for(User) do
      remove :language
    end
    EOF
  end
  
  if yes? "Do you want to run the new migration now? [y/N]", :green
    say "Running migration", :yellow
    run "lucky db.setup"
    run "lucky db.migrate"
  end
end

say "Adding i18n Shard to shard.yml", :yellow
insert_into_file "shard.yml", after: "dependencies:\n" do
  <<-EOF
  i18n:
    github: TechMagister/i18n.cr
  EOF
end

say "Requiring i18n shard in src/shards.cr", :yellow
append_to_file "src/shards.cr" do
  <<~EOF
    require "i18n"
  EOF
end

say "Installing shards", :yellow
run "shards install"

say "Creating config/locales for translations", :yellow
create_file "config/locales/.keep"

initial_language_code = ask "Which country code would you like the default config file generated for?", :green, default: "en"
hello_translation = ask "How do you say 'Hello' in that country?", :green, default: "Hello"
create_file "config/locales/#{initial_language_code}.yml" do
  <<~EOF
    # t("simple_example.hello")
    # => "Hello"
    simple_example:
      hello: "#{hello_translation}"
    
    # t("interpolation_example.hello", { username: "LuckyCasts" })
    # => "Hello, LuckyCasts"
    interpolation_example:
      hello: "#{hello_translation}, %{username}"
    
    # t("count_example.apple", count: 2)
    # => "2 apples"
    count_example:
      apple:
        one: "%{count} apple"
        other: "%{count} apples"
  EOF
end

say "Creating i18n.cr to load translations", :yellow
create_file "config/i18n.cr" do
  <<~EOF
    I18n.load_path += ["config/locales/**/"]
    I18n.init
    I18n.default_locale = "#{initial_language_code}"
  EOF
end

if Dir.glob("db/migrations/*add_language_to_user.cr").empty?
  generate_user_language_database_migration(initial_language_code)
else
  say "Migration already exists. Skipping generation", :yellow
end

say "Adding language column to User model file"
insert_into_file "src/models/user.cr", after: "table do\n" do
  <<-EOF
    column language : String
  EOF
end

say "Creating src/translator.cr module for translation logic", :yellow
create_file "src/translator.cr" do
  <<~EOF
    module Translator
      LANGUAGE_DEFAULT    = I18n.default_locale
      LANGUAGES_AVAILABLE = [LANGUAGE_DEFAULT]
      
      # Modify as necessary for other languages. For example:
      # LANGUAGE_DEFAULT = I18n.default_locale
      # LANGUAGES_AVAILABLE = [I18n.default_locale, "es"]
      
      # For more information on options you can pass to I18n.translate:
      # See https://github.com/TechMagister/i18n.cr
      def t(*args, **nargs) 
        I18n.locale = user_language
        I18n.translate(*args, **nargs)
      end

      # In places where current_user / user isn't available, be sure to override this method:
      # quick_def user_language, LANGUAGE_DEFAULT
      def user_language
        current_user.try(&.language) || LANGUAGE_DEFAULT
      end
    end
  EOF
end

say "Requiring new translator module in src/app.cr", :yellow
insert_into_file "src/app.cr", after: "Lucky::AssetHelpers.load_manifest\n\n" do
  <<~EOF
    require "./translator"
  EOF
end

if File.exists?("src/operations/sign_up_user.cr")
  say "Requiring language for new user sign up", :yellow
  
  gsub_file "src/operations/sign_up_user.cr", /permit_columns (.*)$/, "permit_columns language, \\1"
  
  insert_into_file "src/operations/sign_up_user.cr", after: "before_save do\n" do
    <<-EOF
    language.value ||= Translator::LANGUAGE_DEFAULT
    validate_inclusion_of language, in: Translator::LANGUAGES_AVAILABLE
    EOF
  end
end

if File.exists?("src/pages/main_layout.cr")
  say "Including Translator module in MainLayout for use in front end", :yellow
  insert_into_file "src/pages/main_layout.cr", after: "include Lucky::HTMLPage\n" do
    <<-EOF
  include Translator
    EOF
  end
end

if File.exists?("src/pages/auth_layout.cr")
  say "Including Translator module in AuthLayout for use in front end", :yellow
  insert_into_file "src/pages/auth_layout.cr", after: "include Lucky::HTMLPage\n" do
    <<-EOF
  include Translator
  quick_def user_language, LANGUAGE_DEFAULT
    EOF
  end
end

if File.exists?("src/pages/errors/show_page.cr")
  say "Including Translator module in Errors::ShowPage for use in front end", :yellow
  insert_into_file "src/pages/errors/show_page.cr", after: "include Lucky::HTMLPage\n" do
    <<-EOF
  include Translator
  quick_def user_language, LANGUAGE_DEFAULT
    EOF
  end
end

if File.exists?("src/actions/browser_action.cr")
  say "Including Translator module in BrowserAction for use in browser actions", :yellow
  insert_into_file "src/actions/browser_action.cr", after: "abstract class BrowserAction < Lucky::Action\n" do
    <<-EOF
  include Translator\n
    EOF
  end
end

if File.exists?("src/actions/api_action.cr")
  say "Including Translator module in ApiAction for use in API actions", :yellow
  insert_into_file "src/actions/api_action.cr", after: "abstract class ApiAction < Lucky::Action\n" do
    <<-EOF
  include Translator\n
    EOF
  end
end

say "Done! For examples of how to use translations in pages themselves, visit the Lucky Guides here: https://luckyframework.org/guides/frontend/internationalization", :green
Comments

Sign up or Login to leave a comment.