Config flow translations (#13066)

* Development script for testing translation strings

* Localize backend of config flow

* Fix hue tests

* Update hue.en.json

* Move components to individual directories

* Bridge -> bridge
This commit is contained in:
Adam Mills 2018-03-11 15:04:34 -04:00 committed by Paulus Schoutsen
parent f5cc40024d
commit 26960283a0
11 changed files with 147 additions and 41 deletions

View file

@ -0,0 +1,24 @@
{
"config": {
"error": {
"invalid_object_id": "Invalid object ID"
},
"step": {
"init": {
"data": {
"object_id": "Object ID"
},
"description": "Please enter an object_id for the test entity.",
"title": "Pick object id"
},
"name": {
"data": {
"name": "Name"
},
"description": "Please enter a name for the test entity.",
"title": "Name of the entity"
}
},
"title": "Config Entry Example"
}
}

View file

@ -62,13 +62,11 @@ class ExampleConfigFlow(config_entries.ConfigFlowHandler):
return (yield from self.async_step_name())
errors = {
'object_id': 'Invalid object id.'
'object_id': 'invalid_object_id'
}
return self.async_show_form(
title='Pick object id',
step_id='init',
description="Please enter an object_id for the test entity.",
data_schema=vol.Schema({
'object_id': str
}),
@ -92,9 +90,7 @@ class ExampleConfigFlow(config_entries.ConfigFlowHandler):
)
return self.async_show_form(
title='Name of the entity',
step_id='name',
description="Please enter a name for the test entity.",
data_schema=vol.Schema({
'name': str
}),

View file

@ -0,0 +1,24 @@
{
"config": {
"title": "Config Entry Example",
"step": {
"init": {
"title": "Pick object id",
"description": "Please enter an object_id for the test entity.",
"data": {
"object_id": "Object ID"
}
},
"name": {
"title": "Name of the entity",
"description": "Please enter a name for the test entity.",
"data": {
"name": "Name"
}
}
},
"error": {
"invalid_object_id": "Invalid object ID"
}
}
}

View file

@ -0,0 +1,26 @@
{
"config": {
"abort": {
"all_configured": "All Philips Hue bridges are already configured",
"discover_timeout": "Unable to discover Hue bridges",
"no_bridges": "No Philips Hue bridges discovered"
},
"error": {
"linking": "Unknown linking error occurred.",
"register_failed": "Failed to register, please try again"
},
"step": {
"init": {
"data": {
"host": "Host"
},
"title": "Pick Hue bridge"
},
"link": {
"description": "Press the button on the bridge to register Philips Hue with Home Assistant.\n\n![Location of button on bridge](/static/images/config_philips_hue.jpg)",
"title": "Link Hub"
}
},
"title": "Philips Hue Bridge"
}
}

View file

@ -304,12 +304,12 @@ class HueFlowHandler(config_entries.ConfigFlowHandler):
bridges = await discover_nupnp(websession=self._websession)
except asyncio.TimeoutError:
return self.async_abort(
reason='Unable to discover Hue bridges.'
reason='discover_timeout'
)
if not bridges:
return self.async_abort(
reason='No Philips Hue bridges discovered.'
reason='no_bridges'
)
# Find already configured hosts
@ -322,7 +322,7 @@ class HueFlowHandler(config_entries.ConfigFlowHandler):
if not hosts:
return self.async_abort(
reason='All Philips Hue bridges are already configured.'
reason='all_configured'
)
elif len(hosts) == 1:
@ -331,7 +331,6 @@ class HueFlowHandler(config_entries.ConfigFlowHandler):
return self.async_show_form(
step_id='init',
title='Pick Hue Bridge',
data_schema=vol.Schema({
vol.Required('host'): vol.In(hosts)
})
@ -352,10 +351,10 @@ class HueFlowHandler(config_entries.ConfigFlowHandler):
await bridge.initialize()
except (asyncio.TimeoutError, aiohue.RequestError,
aiohue.LinkButtonNotPressed):
errors['base'] = 'Failed to register, please try again.'
errors['base'] = 'register_failed'
except aiohue.AiohueException:
errors['base'] = 'Unknown linking error occurred.'
_LOGGER.exception('Uknown Hue linking error occurred')
errors['base'] = 'linking'
_LOGGER.exception('Unknown Hue linking error occurred')
else:
return self.async_create_entry(
title=bridge.config.name,
@ -368,8 +367,6 @@ class HueFlowHandler(config_entries.ConfigFlowHandler):
return self.async_show_form(
step_id='link',
title='Link Hub',
description=CONFIG_INSTRUCTIONS,
errors=errors,
)

View file

@ -0,0 +1,26 @@
{
"config": {
"title": "Philips Hue Bridge",
"step": {
"init": {
"title": "Pick Hue bridge",
"data": {
"host": "Host"
}
},
"link": {
"title": "Link Hub",
"description": "Press the button on the bridge to register Philips Hue with Home Assistant.\n\n![Location of button on bridge](/static/images/config_philips_hue.jpg)"
}
},
"error": {
"register_failed": "Failed to register, please try again",
"linking": "Unknown linking error occurred."
},
"abort": {
"discover_timeout": "Unable to discover Hue bridges",
"no_bridges": "No Philips Hue bridges discovered",
"all_configured": "All Philips Hue bridges are already configured"
}
}
}

View file

@ -442,7 +442,7 @@ class FlowManager:
'Handler returned incorrect type: {}'.format(result['type']))
if result['type'] == RESULT_TYPE_FORM:
flow.cur_step = (result.pop('step_id'), result['data_schema'])
flow.cur_step = (result['step_id'], result['data_schema'])
return result
# Abort and Success results both finish the flow
@ -468,6 +468,7 @@ class ConfigFlowHandler:
# Set by flow manager
flow_id = None
hass = None
domain = None
source = SOURCE_USER
cur_step = None
@ -475,15 +476,13 @@ class ConfigFlowHandler:
# VERSION
@callback
def async_show_form(self, *, title, step_id, description=None,
data_schema=None, errors=None):
def async_show_form(self, *, step_id, data_schema=None, errors=None):
"""Return the definition of a form to gather user input."""
return {
'type': RESULT_TYPE_FORM,
'flow_id': self.flow_id,
'title': title,
'domain': self.domain,
'step_id': step_id,
'description': description,
'data_schema': data_schema,
'errors': errors,
}
@ -494,6 +493,7 @@ class ConfigFlowHandler:
return {
'type': RESULT_TYPE_CREATE_ENTRY,
'flow_id': self.flow_id,
'domain': self.domain,
'title': title,
'data': data,
}
@ -504,5 +504,6 @@ class ConfigFlowHandler:
return {
'type': RESULT_TYPE_ABORT,
'flow_id': self.flow_id,
'domain': self.domain,
'reason': reason
}

21
script/translations_develop Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Compile the current translation strings files for testing
# Safe bash settings
# -e Exit on command fail
# -u Exit on unset variable
# -o pipefail Exit if piped command has error code
set -eu -o pipefail
cd "$(dirname "$0")/.."
mkdir -p build/translations-download
script/translations_upload_merge.py
# Use the generated translations upload file as the mock output from the
# Lokalise download
mv build/translations-upload.json build/translations-download/en.json
script/translations_download_split.py

View file

@ -101,9 +101,7 @@ def test_initialize_flow(hass, client):
schema[vol.Required('password')] = str
return self.async_show_form(
title='test-title',
step_id='init',
description='test-description',
data_schema=schema,
errors={
'username': 'Should be unique.'
@ -121,8 +119,8 @@ def test_initialize_flow(hass, client):
assert data == {
'type': 'form',
'title': 'test-title',
'description': 'test-description',
'domain': 'test',
'step_id': 'init',
'data_schema': [
{
'name': 'username',
@ -157,6 +155,7 @@ def test_abort(hass, client):
data = yield from resp.json()
data.pop('flow_id')
assert data == {
'domain': 'test',
'reason': 'bla',
'type': 'abort'
}
@ -186,6 +185,7 @@ def test_create_account(hass, client):
data = yield from resp.json()
data.pop('flow_id')
assert data == {
'domain': 'test',
'title': 'Test Entry',
'type': 'create_entry'
}
@ -203,7 +203,6 @@ def test_two_step_flow(hass, client):
@asyncio.coroutine
def async_step_init(self, user_input=None):
return self.async_show_form(
title='test-title',
step_id='account',
data_schema=vol.Schema({
'user_title': str
@ -224,8 +223,8 @@ def test_two_step_flow(hass, client):
flow_id = data.pop('flow_id')
assert data == {
'type': 'form',
'title': 'test-title',
'description': None,
'domain': 'test',
'step_id': 'account',
'data_schema': [
{
'name': 'user_title',
@ -243,6 +242,7 @@ def test_two_step_flow(hass, client):
data = yield from resp.json()
data.pop('flow_id')
assert data == {
'domain': 'test',
'type': 'create_entry',
'title': 'user-title',
}
@ -262,7 +262,6 @@ def test_get_progress_index(hass, client):
def async_step_account(self, user_input=None):
return self.async_show_form(
step_id='account',
title='Finish setup'
)
with patch.dict(HANDLERS, {'test': TestFlow}):
@ -292,9 +291,7 @@ def test_get_progress_flow(hass, client):
schema[vol.Required('password')] = str
return self.async_show_form(
title='test-title',
step_id='init',
description='test-description',
data_schema=schema,
errors={
'username': 'Should be unique.'

View file

@ -552,7 +552,7 @@ async def test_flow_link_timeout(hass):
assert result['type'] == 'form'
assert result['step_id'] == 'link'
assert result['errors'] == {
'base': 'Failed to register, please try again.'
'base': 'register_failed'
}
@ -568,7 +568,7 @@ async def test_flow_link_button_not_pressed(hass):
assert result['type'] == 'form'
assert result['step_id'] == 'link'
assert result['errors'] == {
'base': 'Failed to register, please try again.'
'base': 'register_failed'
}
@ -584,5 +584,5 @@ async def test_flow_link_unknown_host(hass):
assert result['type'] == 'form'
assert result['step_id'] == 'link'
assert result['errors'] == {
'base': 'Failed to register, please try again.'
'base': 'register_failed'
}

View file

@ -226,14 +226,14 @@ def test_configure_reuses_handler_instance(manager):
def async_step_init(self, user_input=None):
self.handle_count += 1
return self.async_show_form(
title=str(self.handle_count),
errors={'base': str(self.handle_count)},
step_id='init')
with patch.dict(config_entries.HANDLERS, {'test': TestFlow}):
form = yield from manager.flow.async_init('test')
assert form['title'] == '1'
assert form['errors']['base'] == '1'
form = yield from manager.flow.async_configure(form['flow_id'])
assert form['title'] == '2'
assert form['errors']['base'] == '2'
assert len(manager.flow.async_progress()) == 1
assert len(manager.async_entries()) == 0
@ -250,7 +250,6 @@ def test_configure_two_steps(manager):
self.init_data = user_input
return self.async_step_second()
return self.async_show_form(
title='title',
step_id='init',
data_schema=vol.Schema([str])
)
@ -263,7 +262,6 @@ def test_configure_two_steps(manager):
data=self.init_data + user_input
)
return self.async_show_form(
title='title',
step_id='second',
data_schema=vol.Schema([str])
)
@ -299,9 +297,7 @@ def test_show_form(manager):
@asyncio.coroutine
def async_step_init(self, user_input=None):
return self.async_show_form(
title='Hello form',
step_id='init',
description='test-description',
data_schema=schema,
errors={
'username': 'Should be unique.'
@ -311,8 +307,6 @@ def test_show_form(manager):
with patch.dict(config_entries.HANDLERS, {'test': TestFlow}):
form = yield from manager.flow.async_init('test')
assert form['type'] == 'form'
assert form['title'] == 'Hello form'
assert form['description'] == 'test-description'
assert form['data_schema'] is schema
assert form['errors'] == {
'username': 'Should be unique.'