middleman/middleman-core/lib/middleman-core/core_extensions/i18n.rb

186 lines
6 KiB
Ruby
Raw Normal View History

2013-04-20 23:58:06 +02:00
class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
option :no_fallbacks, false, 'Disable I18n fallbacks'
option :langs, nil, 'List of langs, will autodiscover by default'
option :lang_map, {}, 'Language shortname map'
option :path, '/:locale/', 'URL prefix path'
option :templates_dir, 'localizable', 'Location of templates to be localized'
option :mount_at_root, nil, 'Mount a specific language at the root of the site'
option :data, 'locales', 'The directory holding your locale configurations'
2013-04-20 23:58:06 +02:00
2014-07-06 01:50:19 +02:00
def after_configuration
2013-04-20 23:58:06 +02:00
# See https://github.com/svenfuchs/i18n/wiki/Fallbacks
unless options[:no_fallbacks]
require 'i18n/backend/fallbacks'
2013-04-20 23:58:06 +02:00
::I18n::Backend::Simple.send(:include, ::I18n::Backend::Fallbacks)
end
2014-03-26 00:54:16 +01:00
locales_file_path = options[:data]
2014-07-16 03:01:45 +02:00
# Tell the file watcher to observe the :data_dir
app.files.watch :locales,
path: File.join(app.root, locales_file_path),
ignore: proc { |f| !(/.*(rb|yml|yaml)$/.match(f[:relative_path])) }
2012-03-11 04:40:04 +01:00
2014-07-16 03:01:45 +02:00
# Setup data files before anything else so they are available when
# parsing config.rb
app.files.changed(:locales, &method(:on_file_changed))
2013-04-20 23:58:06 +02:00
@maps = {}
@mount_at_root = options[:mount_at_root].nil? ? langs.first : options[:mount_at_root]
2013-04-20 23:58:06 +02:00
# Don't output localizable files
app.ignore File.join(options[:templates_dir], '**')
2014-07-16 03:01:45 +02:00
configure_i18n
logger.info "== Locales: #{langs.join(', ')} (Default #{@mount_at_root})"
2013-04-20 23:58:06 +02:00
end
helpers do
2013-04-20 23:58:06 +02:00
def t(*args)
::I18n.t(*args)
end
2014-08-14 19:14:26 +02:00
def locate_partial(partial_name)
locals_dir = extensions[:i18n].options[:templates_dir]
# Try /localizable
partials_path = File.join(locals_dir, partial_name)
2014-08-14 19:14:26 +02:00
lang_suffix = current_resource.metadata[:locals] && current_resource.metadata[:locals][:lang]
extname = File.extname(partial_name)
maybe_static = extname.length > 0
suffixed_partial_name = if maybe_static
partial_name.sub(extname, ".#{lang_suffix}#{extname}")
else
"#{partial_name}.#{lang_suffix}"
end
if lang_suffix
super(suffixed_partial_name) ||
super(File.join(locals_dir, suffixed_partial_name)) ||
super(partials_path) ||
super
else
super(partials_path) ||
super
end
end
2013-04-20 23:58:06 +02:00
end
2014-07-03 04:04:34 +02:00
Contract None => ArrayOf[Symbol]
2013-04-20 23:58:06 +02:00
def langs
@langs ||= known_languages
2013-04-20 23:58:06 +02:00
end
2013-10-29 00:42:08 +01:00
2013-04-20 23:58:06 +02:00
# Update the main sitemap resource list
2014-07-03 04:04:34 +02:00
# @return Array<Middleman::Sitemap::Resource>
Contract ResourceList => ResourceList
2013-04-20 23:58:06 +02:00
def manipulate_resource_list(resources)
new_resources = []
2013-04-20 23:58:06 +02:00
resources.each do |resource|
2013-11-19 09:17:50 +01:00
# If it uses file extension localization
if result = parse_locale_extension(resource.path)
2014-04-29 01:02:18 +02:00
ext_lang, path, page_id = result
new_resources << build_resource(path, resource.path, page_id, ext_lang)
# If it's a "localizable template"
elsif File.fnmatch?(File.join(options[:templates_dir], '**'), resource.path)
page_id = File.basename(resource.path, File.extname(resource.path))
langs.each do |lang|
# Remove folder name
path = resource.path.sub(options[:templates_dir], '')
new_resources << build_resource(path, resource.path, page_id, lang)
end
end
# 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.
2014-07-02 20:05:57 +02:00
next if resource.options[:lang]
resource.add_metadata options: { lang: @mount_at_root }, locals: { lang: @mount_at_root }
end
resources + new_resources
end
private
2014-07-16 03:01:45 +02:00
Contract Any, Any => Any
def on_file_changed(_updated_files, _removed_files)
2014-07-02 19:11:52 +02:00
@_langs = nil # Clear langs cache
2013-10-29 00:42:08 +01:00
2014-07-16 03:01:45 +02:00
# TODO, add new file to ::I18n.load_path
::I18n.reload!
end
def configure_i18n
2014-07-16 03:01:45 +02:00
::I18n.load_path += app.files.by_type(:locales).files.map { |p| p[:full_path].to_s }
::I18n.reload!
::I18n.default_locale = @mount_at_root
2014-07-02 19:11:52 +02:00
# Reset fallbacks to fall back to our new default
2014-07-02 19:11:52 +02:00
::I18n.fallbacks = ::I18n::Locale::Fallbacks.new if ::I18n.respond_to?(:fallbacks)
end
2014-07-03 04:04:34 +02:00
Contract None => ArrayOf[Symbol]
2014-04-29 19:44:24 +02:00
def known_languages
if options[:langs]
Array(options[:langs]).map(&:to_sym)
else
2014-07-16 03:01:45 +02:00
known_langs = app.files.by_type(:locales).files.select do |p|
p[:relative_path].to_s.split(File::SEPARATOR).length == 1
2014-04-29 01:02:18 +02:00
end
known_langs.map { |p|
2014-07-16 03:01:45 +02:00
File.basename(p[:relative_path].to_s).sub(/\.ya?ml$/, '').sub(/\.rb$/, '')
}.sort.map(&:to_sym)
end
end
# Parse locale extension filename
2013-05-03 07:03:28 +02:00
# @return [lang, path, basename]
# will return +nil+ if no locale extension
2014-07-03 04:04:34 +02:00
Contract String => Maybe[[Symbol, String, String]]
def parse_locale_extension(path)
2013-05-03 07:03:28 +02:00
path_bits = path.split('.')
return nil if path_bits.size < 3
lang = path_bits.delete_at(-2).to_sym
return nil unless langs.include?(lang)
path = path_bits.join('.')
basename = File.basename(path_bits[0..-2].join('.'))
[lang, path, basename]
end
2014-07-03 04:04:34 +02:00
Contract String, String, String, Symbol => IsA['Middleman::Sitemap::Resource']
def build_resource(path, source_path, page_id, lang)
old_locale = ::I18n.locale
::I18n.locale = lang
2014-04-29 19:50:21 +02:00
localized_page_id = ::I18n.t("paths.#{page_id}", default: page_id, fallback: [])
2013-04-20 23:58:06 +02:00
2014-04-29 19:50:21 +02:00
prefix = if (options[:mount_at_root] == lang) || (options[:mount_at_root].nil? && langs[0] == lang)
'/'
else
replacement = options[:lang_map].fetch(lang, lang)
options[:path].sub(':locale', replacement.to_s)
end
2013-04-20 23:58:06 +02:00
2013-10-29 00:42:08 +01:00
# path needs to be changed if file has a localizable extension. (options[mount_at_root] == lang)
path = ::Middleman::Util.normalize_path(
File.join(prefix, path.sub(page_id, localized_page_id))
)
2013-04-20 23:58:06 +02:00
2014-04-28 08:05:18 +02:00
path = path.sub(options[:templates_dir] + '/', '')
2013-10-29 00:42:08 +01:00
p = ::Middleman::Sitemap::ProxyResource.new(app.sitemap, path, source_path)
p.add_metadata locals: { lang: lang, page_id: path }, options: { lang: lang }
2013-04-20 23:58:06 +02:00
::I18n.locale = old_locale
p
2012-03-11 04:40:04 +01:00
end
end