From 7b89865b0d2bd43d067a0197d789c0ff35dda371 Mon Sep 17 00:00:00 2001 From: Ashwin Maroli Date: Fri, 21 Sep 2018 17:07:24 +0530 Subject: [PATCH] Initial Commit :tada: --- .gitignore | 10 +++++ .rubocop.yml | 8 ++++ Gemfile | 6 +++ LICENSE.txt | 21 ++++++++++ README.md | 3 ++ jekyll-locale.gemspec | 27 +++++++++++++ lib/jekyll-locale.rb | 15 +++++++ lib/jekyll/locale/drop.rb | 10 +++++ lib/jekyll/locale/handler.rb | 42 ++++++++++++++++++++ lib/jekyll/locale/version.rb | 7 ++++ lib/jekyll/patches/site.rb | 15 +++++++ lib/jekyll/patches/utils.rb | 76 ++++++++++++++++++++++++++++++++++++ 12 files changed, 240 insertions(+) create mode 100644 .gitignore create mode 100644 .rubocop.yml create mode 100644 Gemfile create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 jekyll-locale.gemspec create mode 100644 lib/jekyll-locale.rb create mode 100644 lib/jekyll/locale/drop.rb create mode 100644 lib/jekyll/locale/handler.rb create mode 100644 lib/jekyll/locale/version.rb create mode 100644 lib/jekyll/patches/site.rb create mode 100644 lib/jekyll/patches/utils.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c27940 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +_site +.logs +.sass-cache +.jekyll-cache +.fixtures +.gems +.vendor +.jekyll-metadata +Gemfile.lock +*.gem diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..75be182 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,8 @@ +require: rubocop-jekyll +inherit_gem: + rubocop-jekyll: .rubocop.yml + +Metrics/CyclomaticComplexity: + Max: 7 +Style/ClassAndModuleChildren: + Enabled: false diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1a7dc53 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +gemspec + +gem "rubocop-jekyll" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3f644a1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Ashwin Maroli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3cb352 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Jekyll Locale + +A localization plugin for Jekyll diff --git a/jekyll-locale.gemspec b/jekyll-locale.gemspec new file mode 100644 index 0000000..3e7bd66 --- /dev/null +++ b/jekyll-locale.gemspec @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +lib = File.expand_path("lib", __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "jekyll/locale/version" + +Gem::Specification.new do |spec| + spec.name = "jekyll-locale" + spec.version = Jekyll::Locale::VERSION + spec.authors = ["Ashwin Maroli"] + spec.email = ["ashmaroli@gmail.com"] + + spec.summary = "A localization plugin for Jekyll" + spec.homepage = "https://github.com/ashmaroli/jekyll-locale" + spec.license = "MIT" + + spec.metadata = { "allowed_push_host" => "https://rubygems.org" } + + spec.files = `git ls-files -z`.split("\x0").select do |f| + f.match(%r!^(lib/|(LICENSE|README)((\.(txt|md|markdown)|$)))!i) + end + + spec.require_paths = ["lib"] + spec.required_ruby_version = ">= 2.3.0" + + spec.add_runtime_dependency "jekyll", "~> 3.8" +end diff --git a/lib/jekyll-locale.rb b/lib/jekyll-locale.rb new file mode 100644 index 0000000..9dae340 --- /dev/null +++ b/lib/jekyll-locale.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Jekyll + module Locale + autoload :Drop, "jekyll/locale/drop" + autoload :Handler, "jekyll/locale/handler" + end +end + +require_relative "jekyll/patches/site" +require_relative "jekyll/patches/utils" + +Jekyll::Hooks.register :site, :after_reset do |site| + site.locale_handler.reset +end diff --git a/lib/jekyll/locale/drop.rb b/lib/jekyll/locale/drop.rb new file mode 100644 index 0000000..3329f4b --- /dev/null +++ b/lib/jekyll/locale/drop.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Jekyll + class Locale::Drop < Drops::Drop + extend Forwardable + + mutable false + private def_delegator :@obj, :data, :fallback_data + end +end diff --git a/lib/jekyll/locale/handler.rb b/lib/jekyll/locale/handler.rb new file mode 100644 index 0000000..c98048b --- /dev/null +++ b/lib/jekyll/locale/handler.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Jekyll + class Locale::Handler + def initialize(site) + @site = site + @config = site.config + end + + def reset + @data = nil + end + + def data + @data ||= begin + fallback = site.site_data.dig(locales_dir, locale) + return {} unless fallback.is_a?(Hash) + + # transform hash to one with "latinized lowercased string keys" + Jekyll::Utils.snake_case_keys(fallback) + end + end + + private + + attr_reader :site, :config + + def locales_dir + @locales_dir ||= begin + value = config["locales_dir"] + value.to_s.empty? ? "locales" : value + end + end + + def locale + @locale ||= begin + value = config["locale"] + value.to_s.empty? ? "en" : value + end + end + end +end diff --git a/lib/jekyll/locale/version.rb b/lib/jekyll/locale/version.rb new file mode 100644 index 0000000..0f3be91 --- /dev/null +++ b/lib/jekyll/locale/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Jekyll + module Locale + VERSION = "0.1.0" + end +end diff --git a/lib/jekyll/patches/site.rb b/lib/jekyll/patches/site.rb new file mode 100644 index 0000000..eceaaa1 --- /dev/null +++ b/lib/jekyll/patches/site.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Jekyll + class Drops::UnifiedPayloadDrop + def locale + @locale ||= Jekyll::Locale::Drop.new(@obj.locale_handler) + end + end + + class Site + def locale_handler + @locale_handler ||= Jekyll::Locale::Handler.new(self) + end + end +end diff --git a/lib/jekyll/patches/utils.rb b/lib/jekyll/patches/utils.rb new file mode 100644 index 0000000..ff90682 --- /dev/null +++ b/lib/jekyll/patches/utils.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + extend self + + # Convert all keys to snake_case by substituting non-alphanumeric characters + # with an underscore. + # The keys are first converted to lowercase strings and then any letters with accents + # are replaced with their plaintext counterpart + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with snake_cased keys or a hash with stringified keys. + def snake_case_keys(hash) + transform_keys(hash) do |key| + begin + Utils.slugify(key.to_s, :mode => "latin", :replacement => "_") + rescue StandardError + key.to_s + end + end + end + + def slugify(string, mode: nil, cased: false, replacement: "-") + mode ||= "default" + return nil if string.nil? + + unless SLUGIFY_MODES.include?(mode) + return cased ? string : string.downcase + end + + # Drop accent marks from latin characters. Everything else turns to ? + if mode == "latin" + I18n.config.available_locales = :en if I18n.config.available_locales.empty? + string = I18n.transliterate(string) + end + + slug = replace_character_sequence(string, :mode => mode, :replacement => replacement) + + # Remove leading/trailing hyphen + slug.gsub!(%r!^\-|\-$!i, "") + + slug.downcase! unless cased + slug + end + + private + + # Replace each character sequence with a hyphen. + # + # See Utils#slugify for a description of the character sequence specified + # by each mode. + def replace_character_sequence(string, **opts) + replaceable_char = + case opts[:mode] + when "raw" + SLUGIFY_RAW_REGEXP + when "pretty" + # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL + # and is allowed in both extN and NTFS. + SLUGIFY_PRETTY_REGEXP + when "ascii" + # For web servers not being able to handle Unicode, the safe + # method is to ditch anything else but latin letters and numeric + # digits. + SLUGIFY_ASCII_REGEXP + else + SLUGIFY_DEFAULT_REGEXP + end + + # Strip according to the mode + string.gsub(replaceable_char, opts[:replacement]) + end + end +end