Skip to content
This repository has been archived by the owner on May 8, 2024. It is now read-only.

Add Localize Helpers #62

Merged
merged 2 commits into from
Dec 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Removes `middleman-blog` dependency[#9](https://github.com/contentful-labs/contentful_middleman/issues/9)
* Add Webhook Integration[#55](https://github.com/contentful-labs/contentful_middleman/pull/55)
* Clarify that `:all_entries` may need an `:order` attribute in the `:cda_query` for avoiding entry skipping and provided a sane default[#60](https://github.com/contentful/contentful_middleman/issues/60)
* Add Localize Helpers

## 1.1.1
### Changed
Expand Down
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,74 @@ For Kramdown this would be:
```
<%= Kramdown::Document.new(data).to_html %>
```

### Locales

If you have localized entries, and want to display content for multiple locales.
You can now include `locale: '*'` in your CDA query.

Then you have the following methods of accessing locales:

* **Manual access**

You can access your localized fields by fetching the locale directly from the data

```html
<h1>Partners</h1>
<ol>
<% data.partners.partner.each do |id, partner| %>
<li><%= partner["name"]['en-US'] %></li>
<% end %>
</ol>
```

* **Entry Helper**

You can also map an specific locale for all entry fields using `localize_entry`

```html
<h1>Partners</h1>
<ol>
<% data.partners.partner.each do |id, partner| %>
<% localized_partner = localize_entry(partner, 'es') %>
<li><%= localized_partner["name"] %></li>
<% end %>
</ol>
```

* **Generic Field Helper**

The `localize` helper will map an specific locale to a field of your entry

```html
<h1>Partners</h1>
<ol>
<% data.partners.partner.each do |id, partner| %>
<li>Value Field: <%= localize(partner, 'name', 'en-US') %></li>
<li>Array Field: <%= localize(partner, 'phones', 'es') %></li>
<% end %>
</ol>
```

* **Specific Field Type Helper**

Or, you can use `localize_value` or `localize_array` if you want more granularity.

> This method is discouraged, as `localize` achieves the same goal and is a field-type
agnostic wrapper of these methods.

```html
<h1>Partners</h1>
<ol>
<% data.partners.partner.each do |id, partner| %>
<li>Value Field: <%= localize_value(partner['name'], 'en-US') %></li>
<li>Array Field: <%= localize_array(partner['phones'], 'es') %></li>
<% end %>
</ol>
```

If your fields are not localized, the value of the field will be returned.

In case of the field being localized but no value being set for a given entry, it will use
a fallback locale, by default is `en-US` but can be specified as an additional
parameter in all the mentioned calls.
2 changes: 1 addition & 1 deletion contentful_middleman.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_dependency("middleman-core", ["~> 3.3"])

# Additional dependencies
s.add_dependency("contentful")
s.add_dependency("contentful", '~> 0.8')
s.add_dependency("contentful-webhook-listener", '~> 0.1')

s.add_development_dependency 'rubygems-tasks', '~> 0.2'
Expand Down
29 changes: 29 additions & 0 deletions lib/contentful_middleman/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,34 @@ module Helpers
def contentful_instances
ContentfulMiddleman.instances
end

def localize_entry(entry, locale, fallback_locale='en-US')
localized_entry = {}
entry.each do |field, value|
localized_entry[field] = localize(entry, field, locale, fallback_locale)
end
localized_entry
end

def localize(entry, field, locale, fallback_locale='en-US')
value = entry.fetch(field)

return localize_array(value, locale, fallback_locale) if value.is_a? ::Array
localize_value(value, locale, fallback_locale)
end

def localize_array(value, locale, fallback_locale='en-US')
value.map do |v|
localize_value(v, locale, fallback_locale)
end
end

def localize_value(value, locale, fallback_locale='en-US')
if value.respond_to? :fetch
return value.fetch(locale) if value.key? locale
return value.fetch(fallback_locale)
end
value
end
end
end
2 changes: 1 addition & 1 deletion lib/contentful_middleman/import_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def local_data_files
content_type_name = @content_type_names.fetch(entry.content_type.id).to_s
context = ContentfulMiddleman::Context.new

content_type_mapper = content_type_mapper_class.new(entries)
content_type_mapper = content_type_mapper_class.new(entries, @contentful.options)
content_type_mapper.map(context, entry)

LocalData::File.new(context.to_yaml, File.join(@space_name, content_type_name, entry.id))
Expand Down
8 changes: 4 additions & 4 deletions lib/contentful_middleman/instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def content_types_ids_to_names
end
end

def options
@extension.options
end

private

def all_entries(cda_query)
Expand Down Expand Up @@ -67,9 +71,5 @@ def client_options
client_options[:api_url] = API_PREVIEW_URL if options.use_preview_api
client_options
end

def options
@extension.options
end
end
end
12 changes: 10 additions & 2 deletions lib/contentful_middleman/mappers/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ module Mapper
class Base
attr_reader :entries

def initialize(entries)
def initialize(entries, options)
@entries = entries
@options = options
@children = {}
end

Expand All @@ -24,6 +25,10 @@ def map(context, entry)

private

def has_multiple_locales?
@options.cda_query.fetch(:locale, nil) == '*'
end

def map_field(context, field_name, field_value)
value_mapping = map_value(field_value)
context.set(field_name, value_mapping)
Expand Down Expand Up @@ -56,7 +61,10 @@ def map_asset(asset)

def map_entry_full(entry, context)
context.id = entry.id
entry.fields.each {|k, v| map_field context, k, v}

fields = has_multiple_locales? ? entry.fields_with_locales : entry.fields

fields.each {|k, v| map_field context, k, v}
end

def map_entry(entry)
Expand Down
67 changes: 67 additions & 0 deletions spec/contentful_middleman/helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ class InstanceDouble
end

describe ContentfulMiddleman::Helpers do
let(:entry) do
{
value_field: {
'es' => 'foo',
'en-US' => 'bar'
},
array_field: [
{
'es' => 'foobar',
'en-US' => 'baz'
}
]
}
end

subject { HelpersMock.new }

before(:each) do
Expand All @@ -28,5 +43,57 @@ class InstanceDouble
expect(subject.contentful_instances.size).to eq(2)
end
end

describe 'localization helpers' do
describe '#localize_value' do
it 'returns value if not a hash independently of locale' do
expect(subject.localize_value('foo', 'es')).to eq('foo')
end

describe 'value is a hash' do
it 'returns fallback_locale value if locale not found' do
expect(subject.localize_value({'en-US' => 'foo'}, 'es')).to eq('foo')
expect(subject.localize_value({'de-DE' => 'bar'}, 'es', 'de-DE')).to eq('bar')
end

it 'returns localized value if locale found' do
expect(subject.localize_value({'es' => 'foobar'}, 'es')).to eq('foobar')
end

it 'fails if locale or fallback_locale not found' do
expect { subject.localize_value({'de-DE' => 'baz'}, 'es') }.to raise_error KeyError
end
end
end

describe '#localize_array' do
it 'calls #localize_value for every element in the array' do
expect(subject).to receive(:localize_value).with({'es' => 'foo'}, 'es', 'en-US')

subject.localize_array([{'es' => 'foo'}], 'es')
end
end

describe '#localize' do
it 'calls #localize_value for a value field' do
expect(subject).to receive(:localize_value).with({'es' => 'foo', 'en-US' => 'bar'}, 'es', 'en-US').and_call_original

expect(subject.localize(entry, :value_field, 'es')).to eq('foo')
end

it 'calls #localize_array for an array field' do
expect(subject).to receive(:localize_array).with([{'es' => 'foobar', 'en-US' => 'baz'}], 'es', 'en-US').and_call_original

expect(subject.localize(entry, :array_field, 'es')).to eq(['foobar'])
end
end

it '#localize_entry' do
expect(subject.localize_entry(entry, 'es')).to eq({
value_field: 'foo',
array_field: ['foobar']
})
end
end
end
end
21 changes: 0 additions & 21 deletions spec/contentful_middleman/instance_spec.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
require 'spec_helper'

class OptionsDouble
DEFAULT_OPTIONS = {
space: {id: 'cfexampleapi', name: 'cats'},
access_token: 'b4c0n73n7fu1',
cda_query: {},
content_types: {},
use_preview_api: false,
all_entries: false,
rebuild_on_webhook: false,
webhook_timeout: 300
}

def initialize(options = DEFAULT_OPTIONS)
options.each do |field, value|
define_singleton_method(field.to_sym) do
value
end
end
end
end

class ExtensionDouble
attr_reader :options
def initialize(options = OptionsDouble.new)
Expand Down
72 changes: 58 additions & 14 deletions spec/contentful_middleman/mappers/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,71 @@
client.entries
}
end
subject { described_class.new entries }

let(:entries_localized) do
vcr('mappers/entries_localized') {
client = Contentful::Client.new(
access_token: 'b4c0n73n7fu1',
space: 'cfexampleapi',
dynamic_entries: :auto
)

client.entries(locale: '*', include: 1)
}
end

let(:options) { OptionsDouble.new }
subject { described_class.new entries, options }

describe 'instance methods' do
let(:context) { ContentfulMiddleman::Context.new }

it '#map' do
expect(context.hashize).to eq({})
describe '#map' do
it 'maps entries without multiple locales' do
expect(context.hashize).to eq({})

expected = {
:id=>"6KntaYXaHSyIw8M6eo26OK",
:name=>"Doge",
:image=> {
:title=>"Doge",
:url=> "//images.contentful.com/cfexampleapi/1x0xpXu4pSGS4OukSyWGUK/cc1239c6385428ef26f4180190532818/doge.jpg"
},
:description=>"such json\nwow"
}

subject.map(context, entries.first)

expect(context.hashize).to eq(expected)
end

it 'maps entries with multiple locales' do
subject = described_class.new entries, OptionsDouble.new(cda_query: {locale: '*'})
expect(context.hashize).to eq({})

expected = {
:id=>"6KntaYXaHSyIw8M6eo26OK",
:name=>"Doge",
:image=> {
:title=>"Doge",
:url=> "//images.contentful.com/cfexampleapi/1x0xpXu4pSGS4OukSyWGUK/cc1239c6385428ef26f4180190532818/doge.jpg"
},
:description=>"such json\nwow"
}
expected = {
:id=>"6KntaYXaHSyIw8M6eo26OK",
:name=> {
:'en-US'=>"Doge"
},
:image=>{
:'en-US'=>{
"sys"=>{
"type"=>"Link",
"linkType"=>"Asset",
"id"=>"1x0xpXu4pSGS4OukSyWGUK"
}
}
},
:description=>{
:'en-US'=>"such json\nwow"
}
}

subject.map(context, entries.first)
subject.map(context, entries_localized.first)

expect(context.hashize).to eq(expected)
expect(context.hashize).to eq(expected)
end
end
end

Expand Down
Loading