class Middleman::CoreExtensions::Internationalization

def after_configuration

def after_configuration
  # See https://github.com/svenfuchs/i18n/wiki/Fallbacks
  unless options[:no_fallbacks]
    require 'i18n/backend/fallbacks'
    ::I18n::Backend::Simple.send(:include, ::I18n::Backend::Fallbacks)
  end
  locales_file_path = options[:data]
  # Tell the file watcher to observe the :data_dir
  app.files.watch :locales,
                  path: File.join(app.root, locales_file_path),
                  only: /.*(rb|yml|yaml)$/
  # Setup data files before anything else so they are available when
  # parsing config.rb
  app.files.on_change(:locales, &method(:on_file_changed))
  @maps = {}
  @mount_at_root = options[:mount_at_root].nil? ? locales.first : options[:mount_at_root]
  configure_i18n
  logger.info "== Locales: #{locales.join(', ')} (Default #{@mount_at_root})"
end

def build_resource(path, source_path, page_id, locale)

def build_resource(path, source_path, page_id, locale)
  old_locale = ::I18n.locale
  ::I18n.locale = locale
  localized_page_id = ::I18n.t("paths.#{page_id}", default: page_id, fallback: false)
  partially_localized_path = ''
  File.dirname(path).split('/').each do |path_sub|
    next if path_sub == ''
    partially_localized_path = "#{partially_localized_path}/#{::I18n.t("paths.#{path_sub}", default: path_sub, fallback: false)}"
  end
  path = "#{partially_localized_path}/#{File.basename(path)}"
  prefix = path_root(locale)
  # path needs to be changed if file has a localizable extension. (options[mount_at_root] == locale)
  path = ::Middleman::Util.normalize_path(
    File.join(prefix, path.sub(page_id, localized_page_id))
  )
  path = path.sub(options[:templates_dir] + '/', '')
  ::I18n.locale = old_locale
  LocalizedPageDescriptor.new(path, source_path, locale)
end

def configure_i18n

def configure_i18n
  ::I18n.load_path |= app.files.by_type(:locales).files.map { |p| p[:full_path].to_s }
  ::I18n.reload!
  ::I18n.default_locale = @mount_at_root
  # Reset fallbacks to fall back to our new default
  if ::I18n.respond_to?(:fallbacks)
    ::I18n.fallbacks = ::I18n::Locale::Fallbacks.new(::I18n.default_locale)
  end
end

def initialize(*)

def initialize(*)
  super
  require 'i18n'
  options[:locales] = options[:langs] unless options[:langs].nil?
  options[:locale_map] = options[:lang_map] unless options[:lang_map].nil?
  # Don't fail on invalid locale, that's not what our current
  # users expect.
  ::I18n.enforce_available_locales = false
  # This is for making the tests work - since the tests
  # don't completely reload middleman, I18n.load_path can get
  # polluted with paths from other test app directories that don't
  # exist anymore.
  if ENV['TEST']
    app.after_configuration_eval do
      ::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
      ::I18n.reload!
    end
  end
end

def known_locales

def known_locales
  if options[:locales]
    Array(options[:locales]).map(&:to_sym)
  else
    known_locales = app.files.by_type(:locales).files.select do |p|
      p[:relative_path].to_s.split(File::SEPARATOR).length == 1
    end
    known_locales.map do |p|
      File.basename(p[:relative_path].to_s).sub(/\.ya?ml$/, '').sub(/\.rb$/, '')
    end.sort.map(&:to_sym)
  end
end

def locale

def locale
  ::I18n.locale
end

def locales

def locales
  @locales ||= known_locales
end

def localized_path(path, locale)

def localized_path(path, locale)
  lookup_path = path.dup
  lookup_path << app.config[:index_file] if lookup_path.end_with?('/')
  @lookup[lookup_path] && @lookup[lookup_path][locale]
end

def locate_partial(partial_name, try_static=false)

def locate_partial(partial_name, try_static=false)
  locals_dir = extensions[:i18n].options[:templates_dir]
  # Try /localizable
  partials_path = File.join(locals_dir, partial_name)
  locale_suffix = ::I18n.locale
  extname = File.extname(partial_name)
  maybe_static = !extname.empty?
  suffixed_partial_name = if maybe_static
    partial_name.sub(extname, ".#{locale_suffix}#{extname}")
  else
    "#{partial_name}.#{locale_suffix}"
  end
  if locale_suffix
    super(suffixed_partial_name, maybe_static) ||
      super(File.join(locals_dir, suffixed_partial_name), maybe_static) ||
      super(partials_path, try_static) ||
      super
  else
    super(partials_path, try_static) ||
      super
  end
end

def manipulate_resource_list(resources)

def manipulate_resource_list(resources)
  new_resources = []
  file_extension_resources = resources.select do |resource|
    # Ignore resources which are outside of the localizable directory
    File.fnmatch?(File.join(options[:templates_dir], '**'), resource.path) &&
      parse_locale_extension(resource.path)
  end
  localizable_folder_resources = resources.select do |resource|
    !file_extension_resources.include?(resource) && File.fnmatch?(File.join(options[:templates_dir], '**'), resource.path)
  end
  # If it's a "localizable template"
  localizable_folder_resources.each do |resource|
    next if resource.ignored?
    page_id = File.basename(resource.path, File.extname(resource.path))
    locales.each do |locale|
      # Remove folder name
      path = resource.path.sub(options[:templates_dir], '')
      new_resources << build_resource(path, resource.path, page_id, locale)
    end
    resource.ignore!
    # This is for backwards compatibility with the old provides_metadata-based code
    # that used to be in this extension, but I don't know how much sense it makes.
    # next if resource.options[:locale]
    # $stderr.puts "Defaulting #{resource.path} to #{@mount_at_root}"
    # resource.add_metadata options: { locale: @mount_at_root }, locals: { locale: @mount_at_root }
  end
  # If it uses file extension localization
  file_extension_resources.each do |resource|
    next if resource.ignored?
    result = parse_locale_extension(resource.path)
    ext_locale, path, page_id = result
    new_resources << build_resource(path, resource.path, page_id, ext_locale)
    resource.ignore!
  end
  # This generates a lookup hash that maps the real path (as seen by the web
  # page user) to the paths of the localized versions. The lookup is later
  # used by `url_for '/some/page.html', :locale => :en` and other url
  # helpers.
  #
  # For example (given :mount_at_root => :es) and localized paths:
  #
  # @lookup['/en/magic/stuff.html'] = {:en => '/en/magic/stuff.html', :de => '/de/magisches/zeug.html', :es => '/magico/cosas.html'}
  # @lookup['/de/index.html'] = {:en => '/en/index.html', :de => '/de/index.html', :es => '/index.html'}
  # @lookup['/en/index.html'] = {:en => '/en/index.html', :de => '/de/index.html', :es => '/index.html'}
  # @lookup['/index.html'] = {:en => '/en/index.html', :de => '/de/index.html', :es => '/index.html'}
  #
  # We do this by grouping by the source paths with the locales removed. All
  # the localized pages with the same content in different languages get the
  # same key.
  #
  @source_path_group = new_resources.group_by do |resource|
    # Try to get source path without extension
    _locale, path, _page_id = parse_locale_extension(resource.source_path)
    # If that fails, there is no extension, so we use the original path. We
    # can not use resource.path here, because .path may be translated, so the
    # file names do not match up.
    path ||= resource.source_path
    # This will contain the localizable/ directory, but that does not matter,
    # because it will be contained in both alternatives above, so the
    # grouping key will be correct.
    path
  end
  # Then we walk this grouped hash and generate the lookup table as given
  # above.
  @lookup = {}
  @source_path_group.each do |src_path, resources|
    # For each group we generate a list of the paths the user really sees
    # (e.g. ['/en/index.html', '/de/index.html', '/index.html'])
    exposed_paths = resources.map(&:path)
    # We also generate a map with the same infos, but with the locales as keys.
    # e.g. {:en => '/en/index.html', :de => '/de/index.html', :es => '/index.html'}
    locale_map = resources.each_with_object({}) do |resource, map|
      map[resource.locale] = '/' + resource.path
    end
    # Then we add those to the lookup table, so every path has a
    # cross-reference to any other path in other locales.
    exposed_paths.each do |path|
      @lookup['/' + path] = locale_map
    end
    if @mount_at_root == false
      src_path = src_path.sub(options[:templates_dir] + '/', '')
      @lookup["/#{src_path}"] = locale_map
    end
  end
  new_resources.reduce(resources) do |sum, r|
    r.execute_descriptor(app, sum)
  end
end

def on_file_changed(_updated_files, _removed_files)

def on_file_changed(_updated_files, _removed_files)
  ::I18n.load_path |= app.files.by_type(:locales).files.map { |p| p[:full_path].to_s }
  ::I18n.reload!
  @app.sitemap.rebuild_resource_list!(:touched_locale_file)
end

def parse_locale_extension(path)

def parse_locale_extension(path)
  path_bits = path.split('.')
  return nil if path_bits.size < 3
  locale = path_bits.delete_at(-2).to_sym
  return nil unless locales.include?(locale)
  path = path_bits.join('.')
  basename = File.basename(path_bits[0..-2].join('.'))
  [locale, path, basename]
end

def path_root(locale)

def path_root(locale)
  if (options[:mount_at_root] == locale) || (options[:mount_at_root].nil? && locales[0] == locale)
    '/'
  else
    replacement = options[:locale_map][locale] || locale
    options[:path].sub(':locale', replacement.to_s).sub(':lang', replacement.to_s) # Backward compat
  end
end

def t(*args)

def t(*args)
  ::I18n.t(*args)
end

def url_for(path_or_resource, options={})

def url_for(path_or_resource, options={})
  locale = options.delete(:locale) || ::I18n.locale
  opts = options.dup
  should_relativize = opts.key?(:relative) ? opts[:relative] : config[:relative_links]
  anchor = opts[:anchor]
  # The first call to `super()` is only to find the correct URL. The next
  # call will relativize and add the anchor.
  opts[:relative] = false
  opts[:anchor] = nil
  href = super(path_or_resource, opts)
  final_path = if result = extensions[:i18n].localized_path(href, locale)
    result
  else
    # Should we log the missing file?
    href
  end
  opts[:relative] = should_relativize
  opts[:anchor] = anchor
  begin
    super(final_path, opts)
  rescue RuntimeError
    super(path_or_resource, options)
  end
end