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:
parent
f5cc40024d
commit
26960283a0
11 changed files with 147 additions and 41 deletions
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}),
|
24
homeassistant/components/config_entry_example/strings.json
Normal file
24
homeassistant/components/config_entry_example/strings.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
26
homeassistant/components/hue/.translations/en.json
Normal file
26
homeassistant/components/hue/.translations/en.json
Normal 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",
|
||||
"title": "Link Hub"
|
||||
}
|
||||
},
|
||||
"title": "Philips Hue Bridge"
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
|
26
homeassistant/components/hue/strings.json
Normal file
26
homeassistant/components/hue/strings.json
Normal 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"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
21
script/translations_develop
Executable 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
|
|
@ -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.'
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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.'
|
||||
|
|
Loading…
Add table
Reference in a new issue