[Locale] Added managing locales and locales names are translated by Symfony Intl component

This commit is contained in:
Kamil Kokot 2015-07-31 11:07:20 +02:00
parent 045bfb684d
commit 2a60cffa19
20 changed files with 419 additions and 61 deletions

View file

@ -140,6 +140,7 @@ default:
- Sylius\Bundle\WebBundle\Behat\WebContext
- Sylius\Bundle\MoneyBundle\Behat\MoneyContext
- Sylius\Bundle\ChannelBundle\Behat\ChannelContext
- Sylius\Bundle\LocaleBundle\Behat\LocaleContext
filters:
tags: "@localization"

View file

@ -0,0 +1,58 @@
@localization
Feature: Managing locales
In order to reach customers from different countries
As a store owner
I want to be able to configure locales
Background:
Given there is default currency configured
And there is default channel configured
And there are following locales configured:
| name | enabled |
| German (Germany) | yes |
| English (United States) | no |
| French (France) | yes |
And I am logged in as administrator
Scenario: Seeing index of all locales
Given I am on the dashboard page
When I follow "Locales"
Then I should be on the locale index page
And I should see 3 locales in the list
Scenario: Seeing empty index of locales
Given there are no locales
When I am on the locale index page
Then I should see "There are no locales configured"
Scenario: Accessing the locale adding form
Given I am on the dashboard page
When I follow "Locales"
And I follow "Create locale"
Then I should be on the locale creation page
Scenario: Creating new locale
Given I am on the locale creation page
When I select "Polish (Poland)" from "Name"
And I press "Create"
Then I should be on the locale index page
And I should see "Locale has been successfully created"
Scenario: Listing only available locales during creating a new locale
When I am on the locale creation page
Then I should not see name "German (Germany)" as available choice
And I should not see name "English (United States)" as available choice
Scenario: Enabling locale
Given there is a disabled locale "Polish (Poland)"
And I am on the locale index page
When I click "Enable" near "Polish (Poland)"
Then I should see enabled locale with name "Polish (Poland)" in the list
And I should see "Locale has been successfully enabled"
Scenario: Disabling locale
Given there is an enabled locale "Polish (Poland)"
And I am on the locale index page
When I click "Disable" near "Polish (Poland)"
Then I should see disabled locale with name "Polish (Poland)" in the list
And I should see "Locale has been successfully disabled"

View file

@ -19,15 +19,15 @@ Feature: Locale selection
Scenario: Only enabled locales are visible to the user
Given I am on the store homepage
Then I should see 3 available locales
And I should browse the store in English
And I should browse the store in "English (United States)"
Scenario: Changing the locale in storefront
Given I am on the store homepage
When I change the locale to Polish
Then I should browse the store in Polish
When I change the locale to "Polish (Poland)"
Then I should browse the store in "Polish (Poland)"
Scenario: Switching the locale as a logged in customer
Given I am logged in user
And I am on the store homepage
When I change the locale to German
Then I should browse the store in German
When I change the locale to "German (Germany)"
Then I should browse the store in "German (Germany)"

View file

@ -430,7 +430,16 @@ class CoreContext extends DefaultContext
foreach ($table->getHash() as $data) {
$locale = $repository->createNew();
$locale->setCode($data['code']);
if (isset($data['code'])) {
$locale->setCode($data['code']);
} elseif (isset($data['name'])) {
$code = $this->getLocaleCodeByEnglishLocaleName($data['name']);
$locale->setCode($code);
} else {
throw new \InvalidArgumentException("Locale definition should have either code or name");
}
if (isset($data['enabled'])) {
$locale->setEnabled('yes' === $data['enabled']);

View file

@ -0,0 +1,98 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\CoreBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Sylius\Component\Locale\Model\LocaleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Intl\Intl;
/**
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
class LocaleType extends AbstractResourceType
{
/**
* @var RepositoryInterface
*/
private $localeRepository;
/**
* {@inheritdoc}
*
* @param RepositoryInterface $localeRepository
*/
public function __construct($dataClass, array $validationGroups = array(), RepositoryInterface $localeRepository)
{
$this->localeRepository = $localeRepository;
parent::__construct($dataClass, $validationGroups);
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$self = $this;
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($self) {
// Adding dynamically created code field
$nameOptions = array(
'label' => 'sylius.form.locale.name',
);
$locale = $event->getData();
if ($locale instanceof LocaleInterface && null !== $locale->getCode()) {
$nameOptions['disabled'] = true;
} else {
$nameOptions['choices'] = $self->getAvailableLocales();
}
$form = $event->getForm();
$form->add('code', 'locale', $nameOptions);
}
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sylius_locale';
}
/**
* Should be private, used public to support PHP 5.3
*
* @internal
*
* @return array
*/
public function getAvailableLocales()
{
$availableLocales = Intl::getLocaleBundle()->getLocaleNames();
/** @var LocaleInterface[] $definedLocales */
$definedLocales = $this->localeRepository->findAll();
foreach ($definedLocales as $locale) {
unset($availableLocales[$locale->getCode()]);
}
return $availableLocales;
}
}

View file

@ -27,6 +27,7 @@
<parameter key="sylius.form.type.list.class">Sylius\Bundle\CoreBundle\Form\Type\ListType</parameter>
<parameter key="sylius.form.type.advanced_order.class">Sylius\Bundle\CoreBundle\Form\Type\AdvancedOrderType</parameter>
<parameter key="sylius.form.type.country.class">Sylius\Bundle\CoreBundle\Form\Type\CountryType</parameter>
<parameter key="sylius.form.type.locale.class">Sylius\Bundle\CoreBundle\Form\Type\LocaleType</parameter>
<parameter key="sylius.form.type.shipping_method_choice.class">Sylius\Bundle\CoreBundle\Form\Type\Shipping\ShippingMethodChoiceType</parameter>
@ -117,6 +118,14 @@
<argument type="service" id="sylius.repository.country" />
<tag name="form.type" alias="sylius_country" />
</service>
<service id="sylius.form.type.locale" class="%sylius.form.type.locale.class%">
<argument>%sylius.model.locale.class%</argument>
<argument type="collection">
<argument>sylius</argument>
</argument>
<argument type="service" id="sylius.repository.locale" />
<tag name="form.type" alias="sylius_locale" />
</service>
<!-- filters -->
<service id="sylius.form.type.customer_filter" class="%sylius.form.type.customer_filter.class%">

View file

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\LocaleBundle\Behat;
use Sylius\Bundle\ResourceBundle\Behat\DefaultContext;
use Sylius\Component\Locale\Model\LocaleInterface;
/**
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
class LocaleContext extends DefaultContext
{
/**
* @Given /^there is a disabled locale "([^""]*)"$/
*/
public function thereIsDisabledLocale($name)
{
$this->thereIsLocale($name, false);
}
/**
* @Given /^I created locale "([^""]*)"$/
* @Given /^there is locale "([^""]*)"$/
* @Given /^there is an enabled locale "([^""]*)"$/
*/
public function thereIsLocale($name, $enabled = true, $flush = true)
{
$code = $this->getLocaleCodeByEnglishLocaleName($name);
/* @var $locale LocaleInterface */
if (null === $locale = $this->getRepository('locale')->findOneBy(array('code' => $code))) {
$locale = $this->getRepository('locale')->createNew();
$locale->setCode(trim($code));
$locale->setEnabled($enabled);
$manager = $this->getEntityManager();
$manager->persist($locale);
if ($flush) {
$manager->flush();
}
}
return $locale;
}
}

View file

@ -91,7 +91,7 @@ class Configuration implements ConfigurationInterface
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue('Sylius\Bundle\LocaleBundle\Form\Type\LocaleType')->end()
->scalarNode('choice')->defaultValue('Sylius\Bundle\ResourceBundle\Form\Type\ResourceChoiceType')->end()
->scalarNode('choice')->defaultValue('Sylius\Bundle\ResourceBundle\Form\Type\LocaleChoiceType')->end()
->end()
->end()
->end()

View file

@ -40,5 +40,10 @@ class SyliusLocaleExtension extends AbstractResourceExtension
$definition = $container->findDefinition('sylius.context.locale');
$definition->replaceArgument(0, new Reference($config['storage']));
$container
->getDefinition('sylius.form.type.locale_choice')
->addArgument(new Reference('sylius.repository.locale'))
;
}
}

View file

@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\LocaleBundle\Form\Type;
use Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
class LocaleChoiceType extends AbstractType
{
/**
* @var ObjectRepository
*/
protected $localeRepository;
/**
* @param ObjectRepository $repository
*/
public function __construct(ObjectRepository $repository)
{
$this->localeRepository = $repository;
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$localeRepository = $this->localeRepository;
$choiceList = function (Options $options) use ($localeRepository) {
if (null === $options['enabled']) {
$choices = $localeRepository->findAll();
} else {
$choices = $localeRepository->findBy(array('enabled' => $options['enabled']));
}
return new ObjectChoiceList($choices, null, array(), null, 'id');
};
$resolver
->setDefaults(array(
'choice_list' => $choiceList,
'enabled' => null,
'label' => 'sylius.form.locale.locale',
'empty_value' => 'sylius.form.locale.select',
))
;
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return 'choice';
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sylius_locale_choice';
}
}

View file

@ -26,11 +26,7 @@ class LocaleType extends AbstractResourceType
{
$builder
->add('code', 'locale', array(
'label' => 'sylius.form.locale.code',
))
->add('enabled', 'checkbox', array(
'required' => false,
'label' => 'sylius.form.locale.enabled',
'label' => 'sylius.form.locale.name',
))
;
}

View file

@ -3,3 +3,4 @@ sylius:
locale:
code: Code
enabled: Enabled
name: Name

View file

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\LocaleBundle\Form\Type;
use Doctrine\Common\Persistence\ObjectRepository;
use PhpSpec\ObjectBehavior;
/**
* @mixin \Sylius\Bundle\LocaleBundle\Form\Type\LocaleChoiceType
*
* @author Kamil Kokot <kamil.kokot@lakion.com>
*/
class LocaleChoiceTypeSpec extends ObjectBehavior
{
function let(ObjectRepository $localeRepository)
{
$this->beConstructedWith($localeRepository);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\LocaleBundle\Form\Type\LocaleChoiceType');
}
function it_is_a_form_type()
{
$this->shouldImplement('Symfony\Component\Form\FormTypeInterface');
}
function it_has_a_valid_name()
{
$this->getName()->shouldReturn('sylius_locale_choice');
}
function it_has_a_parent_type()
{
$this->getParent()->shouldReturn('choice');
}
}

View file

@ -467,4 +467,25 @@ abstract class DefaultContext extends RawMinkContext implements Context, KernelA
return $isoName;
}
/**
* @param string $name
*
* @return string
*
* @throws \InvalidArgumentException If name is not found in locale code registry.
*/
protected function getLocaleCodeByEnglishLocaleName($name)
{
$names = Intl::getLocaleBundle()->getLocaleNames('en');
$code = array_search(trim($name), $names);
if (null === $code) {
throw new \InvalidArgumentException(sprintf(
'Locale "%s" not found! Available names: %s.', $name, join(', ', $names)
));
}
return $code;
}
}

View file

@ -430,14 +430,15 @@ class WebContext extends BaseWebContext implements SnippetAcceptingContext
*/
public function iShouldBrowseTheStoreInLocale($name)
{
$text = 'Welcome to Sylius';
switch ($name) {
case 'English':
$text = 'Welcome to Sylius';
break;
case 'Polish':
case 'Polish (Poland)':
$text = 'Witaj w Sylius';
break;
case 'German':
case 'German (Germany)':
$text = 'Englisch';
break;
}

View file

@ -21,20 +21,18 @@ sylius_backend_locale_create:
template: SyliusWebBundle:Backend/Locale:create.html.twig
redirect: sylius_backend_locale_index
sylius_backend_locale_update:
path: /{id}/edit
methods: [GET, PUT]
sylius_backend_locale_enable:
path: /{id}/enable
methods: [PATCH]
defaults:
_controller: sylius.controller.locale:updateAction
_controller: sylius.controller.locale:enableAction
_sylius:
template: SyliusWebBundle:Backend/Locale:update.html.twig
redirect: sylius_backend_locale_index
sylius_backend_locale_delete:
path: /{id}/delete
methods: [DELETE]
sylius_backend_locale_disable:
path: /{id}/disable
methods: [PATCH]
defaults:
_controller: sylius.controller.locale:deleteAction
_controller: sylius.controller.locale:disableAction
_sylius:
template: SyliusWebBundle:Backend/Misc:delete.html.twig
redirect: sylius_backend_locale_index

View file

@ -462,6 +462,8 @@ sylius:
sku: SKU
updated_at: Last update
locale:
id: ID
name: Name
code: Code
create: Create locale
create_header: Adding new locale

View file

@ -2,6 +2,5 @@
<fieldset>
{{ form_row(form.code, {'attr': {'class': 'input-lg'}}) }}
{{ form_row(form.enabled) }}
</fieldset>
{{ form_widget(form._token) }}

View file

@ -8,24 +8,27 @@
<table class="table">
<thead>
<tr>
<th>{{ sylius_resource_sort('id', 'sylius.locale.id'|trans) }}</th>
<th>{{ 'sylius.locale.name'|trans }}</th>
<th>{{ sylius_resource_sort('code', 'sylius.locale.code'|trans) }}</th>
<th>{{ sylius_resource_sort('enabled', 'sylius.locale.enabled'|trans) }}</th>
<th>{{ sylius_resource_sort('updatedAt', 'sylius.locale.updated_at'|trans) }}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for locale in locales %}
<tr id="{{ locale.id }}">
<tr>
<td>{{ locale.id }}</td>
<td>{{ locale.name }}</td>
<td>{{ locale.code }}</td>
<td>
{{ misc.state_label(locale.enabled) }}
</td>
<td>{{ locale.updatedAt|date }}</td>
<td>{{ misc.state_label(locale.enabled) }}</td>
<td>
<div class="pull-right">
{{ buttons.edit(path('sylius_backend_locale_update', {'id': locale.id})) }}
{{ buttons.delete(path('sylius_backend_locale_delete', {'id': locale.id})) }}
{% if locale.enabled %}
{{ buttons.disable(path('sylius_backend_locale_disable', { 'id': locale.id })) }}
{% else %}
{{ buttons.enable(path('sylius_backend_locale_enable', { 'id': locale.id })) }}
{% endif %}
</div>
</td>
</tr>
@ -33,7 +36,7 @@
</tbody>
</table>
{% else %}
{{ alerts.info('sylius.locale.no_results'|trans) }}
{{ alerts.info('sylius.locale.no_results'|trans) }}
{% endif %}
{% endmacro %}

View file

@ -1,25 +0,0 @@
{% extends 'SyliusWebBundle:Backend:layout.html.twig' %}
{% from 'SyliusResourceBundle:Macros:actions.html.twig' import update %}
{% block topbar %}
<ol class="breadcrumb">
<li>{{ 'sylius.breadcrumb.configuration'|trans }}</li>
<li><a href="{{ path('sylius_backend_locale_index') }}">{{ 'sylius.breadcrumb.locale.index'|trans }}</a></li>
<li>{{ 'sylius.breadcrumb.edit'|trans }}</li>
</ol>
{% endblock %}
{% block content %}
<div class="page-header">
<h1><i class="glyphicon glyphicon-pencil"></i> {{ 'sylius.locale.update_header'|trans|raw }}</h1>
</div>
{{ form_errors(form) }}
<form action="{{ path('sylius_backend_locale_update', {'id': locale.id}) }}" method="post" class="form-horizontal" novalidate>
<input type="hidden" name="_method" value="PUT">
{% include 'SyliusWebBundle:Backend/Locale:_form.html.twig' %}
{{ update() }}
</form>
{% endblock %}