nanoc-filesystem-i18n

filesystem_i18n is a localized data source for a nanoc site. It stores all data as files on the hard disk and is fully compatible with default nanoc data sources Nanoc::DataSources::FilesystemUnified and Nanoc::DataSources::FilesystemVerbose.

Nanoc is a Ruby web publishing system for building small to medium-sized websites. It is a tool that runs on your local computer and compiles documents written in formats such as Markdown, Textile, Haml, Erb, … into a static web site consisting of simple HTML files, ready for uploading to any web server. For more information, please see Nanoc site.

Resources

Documentation

Installation

gem install nanoc-filesystem-i18n

And add following require in your `lib/default.rb` file:

require 'nanoc/data_sources/filesystem_i18n'

Or add following line in your `Gemfile` file:

gem 'nanoc-filesystem-i18n', :require => 'nanoc/data_sources/filesystem_i18n'

Edit `config.yaml` file of your nanoc site and change data_sources type from `filesystem_unified` or `filesystem_verbose` to `filesystem_i18n`:

data_sources:
  -
    type: filesystem_i18n

In the data source section of `config.yaml` file, add following informations:

config:
  locale:
    # list of availables locale, ser default to true to select default
    # locale.
    availables:
      en:
        name: "English"
        default: true
      fr:
        name: "Francais"
    # objects should be not localized
    exclude:
      item: ['/css*', '/js*', '/images*']
      layout: ['*']

See following configuration section for more information.

Data source specifications

The filesystem_i18n data source stores its items and layouts in nested directories or files. Each directory represents a single item or layout, but an item can be a simple file in a directory. The root directory for items is the `content` directory; for layouts it is the `layouts` directory.

Every object (item or layout) is represented by a meta file and one or more content files with a minimum of one file. The content file contains the actual item content or layout, while the meta file contains the item’s or the layout’s metadata, formatted as YAML.

Both meta files and content files are named after its parent directory (i.e. item). For example, an item/layout named `foo` will have a directory named `foo`, with e.g. a `foo.markdown` or `index.markdown` content file and a `foo.yaml` or `index.yaml` meta file. An item/layout named `foo/bar` can be also created in parent directory named `foo` without dedicated directory, with e.g. a `foo.markdown` content file and `foo.yaml` meta file. Root item already named `index.markdown` for content file (extension can be different) and `index.yaml` for meta file.

Content file extensions are not used for determining the filter that should be run; the meta file or configuration file defines the list of filters. The meta file extension must always be `.yaml`, though.

An item/layout content file named `foo.markdown` contain default content for all locales, but you can create a content file for each locales with e.g. a `foo.fr.markdown` for locale `fr`. If default locale for site is `fr` and the `foo.fr.markdown` file is present but `foo.markdow` file not, the `fr` content file is used by default.

The identifier is calculated by stripping the extension (part after last dot) and locale code. The locale code also be added at start of identifier (`foo.fr.html` => `/fr/foo/`), remember this when you configure `Rules` file.

Top level key in meta file is default for all locales, but you can override a metadata for specific locale with following method:

title: Default Item Title
locale:
  fr:
    title: Titre en Français

Configuration

You need to configure available locales in config data source section of `config.yaml` file. The I18n configuration is a hash with `locale` key, and have a `availables` section containing each locale information. If `availables` is set to nil, empty hash or false, the site is not localized and data source work normaly. A locale have it code has key and contain a `name` key and optional `default` key. Set only one locale has default.

config:
  locale:
    availables:
      en:
        name: "English"
        default: true
      fr:
        name: "Francais"

Items and layout can be excluded from localize process by set `exclude` list. It is recommanded to exclude all layouts, css, javascript and design images.

config:
  locale:
    ...
    exclude:
      item: ['/css*', '/js*', '/images*']
      layout: ['*']

Manage locale meta and content

All items have an attribute `locale` now, with the item locale code. Get current locale code in your templates and helpers with `item`.

Rules file

In your `Rules` file, you must remember that identifier have locale code at the beginning.

compile '/*/foo/' do
  filter :erb
  layout 'default'
end

compile '*' do
  filter :erb
  layout 'default'
end

route '/*/foo/' do
  item.identifier.gsub(/\/$/, '') + '.' + item[:extension]
end

route '*' do
  if item.children.size > 0 || item.identifier == '/' || item.identifier == "/#{item[:locale]}/"
    item.identifier + 'index.html'
  else
    item.identifier.gsub(/\/$/, '') + '.' + item[:extension]
  end
end

Locale selection according to navigator accept language

If you deploy your site with Apache server, you can use mod_rewrite to select default locale according to navigator accept language configuration. Create an item named `htaccess.erb` in `content` directory with following content:


locale: false


# For language content negociation, used by css images

Options +MultiViews

RewriteEngine On
RewriteBase /

# Set prefered language from browser preference if available or to default locale
RewriteCond %{HTTP:Accept-Language} ^.*?(<%= I18n.available_locales.map{|l| l.to_s }.join('|') %>).*$ [NC]
RewriteRule ^(.*)$ - [env=prefer-language:%1,S=1]
RewriteRule ^(.*)$ - [env=prefer-language:<%= I18n.default_locale.to_s %>]

# Force prefered language if present in URI
SetEnvIf REQUEST_URI ^/(<%= I18n.available_locales.map{|l| l.to_s }.join('|') %>)(/.+)? prefer-language=$1

# Rewrite root access to prefered language root
RewriteRule ^(/)?$ %{ENV:prefer-language}/ [R=303,L]

# Rewrite other uri to language scope
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !^/(<%= I18n.available_locales.map{|l| l.to_s }.join('|') %>)
RewriteRule ^(.*)$ %{ENV:prefer-language}/$1 [R=303,L]

Add in `Rules` file following compile and route information:

compile '/htaccess*' do
  filter :erb
  # don’t layout
end

route '/htaccess*' do
  '/.htaccess'
end

With this method, visitor on root of your site is redirected to is/her prefered language or default language.

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don't break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)

  • Send me a pull request. Bonus points for topic branches.

Copyright

Copyright © 2010 Yann Lugrin. See LICENSE for details.