Put app strings into a YAML file for easy editing by product owner

This commit is contained in:
George Drummond
2018-12-13 15:02:52 -05:00
parent 8eecb62034
commit f806425d91
35 changed files with 845 additions and 246 deletions

View File

@@ -1,5 +1,6 @@
import re
import datetime
from atst.utils.localization import translate
from flask import current_app as app, render_template
from jinja2.exceptions import TemplateNotFound
@@ -108,3 +109,4 @@ def register_filters(app):
app.jinja_env.filters["dateFromString"] = dateFromString
app.jinja_env.filters["pageWindow"] = pageWindow
app.jinja_env.filters["renderAuditEvent"] = renderAuditEvent
app.jinja_env.filters["translate"] = translate

View File

@@ -5,20 +5,31 @@ from wtforms.validators import Email, Optional
from .forms import CacheableForm
from .validators import Name, PhoneNumber
from atst.utils.localization import translate
class CCPOReviewForm(CacheableForm):
comment = TextAreaField(
"Instructions or comments",
description="Provide instructions or notes for additional information that is necessary to approve the request here. The requestor may then re-submit the updated request or initiate contact outside of AT-AT if further discussion is required. <strong>This message will be shared with the person making the JEDI request.</strong>.",
translate("forms.ccpo_review.comment_label"),
description=("forms.ccpo_review.comment_description"),
)
fname_mao = StringField(
translate("forms.ccpo_review.fname_mao_label"), validators=[Optional(), Name()]
)
lname_mao = StringField(
translate("forms.ccpo_review.lname_mao_label"), validators=[Optional(), Name()]
)
fname_mao = StringField("First Name (optional)", validators=[Optional(), Name()])
lname_mao = StringField("Last Name (optional)", validators=[Optional(), Name()])
email_mao = EmailField(
"Mission Owner e-mail (optional)", validators=[Optional(), Email()]
translate("forms.ccpo_review.email_mao_label"), validators=[Optional(), Email()]
)
phone_mao = TelField(
"Mission Owner phone number (optional)", validators=[Optional(), PhoneNumber()]
translate("forms.ccpo_review.phone_mao_label"),
validators=[Optional(), PhoneNumber()],
)
phone_ext_mao = StringField(translate("forms.ccpo_review.phone_ext_mao_label"))
fname_ccpo = StringField(
translate("forms.ccpo_review.fname_ccpo_label"), validators=[Optional(), Name()]
)
lname_ccpo = StringField(
translate("forms.ccpo_review.lname_ccpo_label"), validators=[Optional(), Name()]
)
phone_ext_mao = StringField("Extension (optional)")
fname_ccpo = StringField("First Name (optional)", validators=[Optional(), Name()])
lname_ccpo = StringField("Last Name (optional)", validators=[Optional(), Name()])

View File

@@ -2,6 +2,7 @@ from flask_wtf import FlaskForm
from wtforms.validators import Required
from atst.forms.fields import SelectField
from atst.utils.localization import translate
from .data import WORKSPACE_ROLES
@@ -11,5 +12,7 @@ class EditMemberForm(FlaskForm):
# that the user is a member of
workspace_role = SelectField(
"Workspace Role", choices=WORKSPACE_ROLES, validators=[Required()]
translate("forms.edit_member.workspace_role_label"),
choices=WORKSPACE_ROLES,
validators=[Required()],
)

View File

@@ -8,27 +8,34 @@ from .fields import SelectField
from .forms import CacheableForm
from .data import SERVICE_BRANCHES
from atst.models.user import User
from atst.utils.localization import translate
from .validators import Name, DateRange, PhoneNumber
USER_FIELDS = {
"first_name": StringField("First Name", validators=[Name()]),
"last_name": StringField("Last Name", validators=[Name()]),
"first_name": StringField(
translate("forms.edit_user.first_name_label"), validators=[Name()]
),
"last_name": StringField(
translate("forms.edit_user.last_name_label"), validators=[Name()]
),
"email": EmailField(
"E-mail Address",
description="Enter your preferred contact e-mail address",
translate("forms.edit_user.email_label"),
description=translate("forms.edit_user.email_description"),
validators=[Email()],
),
"phone_number": TelField("Phone Number", validators=[PhoneNumber()]),
"phone_number": TelField(
translate("forms.edit_user.phone_number_label"), validators=[PhoneNumber()]
),
"phone_ext": StringField("Extension"),
"service_branch": SelectField(
"Service Branch or Agency",
description="Which service or organization do you belong to within the DoD?",
translate("forms.edit_user.service_branch_label"),
description=translate("forms.edit_user.service_branch_description"),
choices=SERVICE_BRANCHES,
),
"citizenship": RadioField(
description="What is your citizenship status?",
description=translate("forms.edit_user.citizenship_description"),
choices=[
("United States", "United States"),
("Foreign National", "Foreign National"),
@@ -36,8 +43,8 @@ USER_FIELDS = {
],
),
"designation": RadioField(
"Designation of Person",
description="What is your designation within the DoD?",
translate("forms.edit_user.designation_label"),
description=translate("forms.edit_user.designation_description"),
choices=[
("military", "Military"),
("civilian", "Civilian"),
@@ -45,8 +52,8 @@ USER_FIELDS = {
],
),
"date_latest_training": DateField(
"Latest Information Assurance (IA) Training Completion Date",
description='To complete the training, you can find it in <a class="icon-link" href="https://iatraining.disa.mil/eta/disa_cac2018/launchPage.htm" target="_blank">Information Assurance Cyber Awareness Challange</a> website.',
translate("forms.edit_user.date_latest_training_label"),
description=translate("forms.edit_user.date_latest_training_description"),
validators=[
DateRange(
lower_bound=pendulum.duration(years=1),

View File

@@ -1,6 +1,9 @@
from atst.utils.localization import translate
class FormValidationError(Exception):
message = "Form validation failed."
message = translate("forms.exceptions.message")
def __init__(self, form):
self.form = form

View File

@@ -8,6 +8,7 @@ from werkzeug.datastructures import FileStorage
from .fields import NewlineListField, SelectField, NumberStringField
from atst.forms.forms import CacheableForm
from atst.utils.localization import translate
from .data import FUNDING_TYPES
from .validators import DateRange
@@ -46,24 +47,26 @@ class TaskOrderForm(CacheableForm):
return valid
number = StringField(
"Task Order Number associated with this request",
description="Include the original Task Order number (including the 000X at the end). Do not include any modification numbers. Note that there may be a lag between approving a task order and when it becomes available in our system.",
translate("forms.financial.number_label"),
description=translate("forms.financial.number_description"),
validators=[InputRequired()],
)
funding_type = SelectField(
description="What is the source of funding?",
description=translate("forms.financial.funding_type_description"),
choices=FUNDING_TYPES,
validators=[InputRequired()],
coerce=coerce_choice,
render_kw={"required": False},
)
funding_type_other = StringField("If other, please specify")
funding_type_other = StringField(
translate("forms.financial.funding_type_other_label")
)
expiration_date = DateField(
"Task Order Expiration Date",
description="Please enter the expiration date for the Task Order",
translate("forms.financial.expiration_date_label"),
description=translate("forms.financial.expiration_date_description"),
validators=[
InputRequired(),
DateRange(
@@ -76,51 +79,51 @@ class TaskOrderForm(CacheableForm):
)
clin_0001 = NumberStringField(
"<dl><dt>CLIN 0001</dt> - <dd>Unclassified IaaS and PaaS Amount</dd></dl>",
translate("forms.financial.clin_0001_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_0001_description"),
filters=[number_to_int],
)
clin_0003 = NumberStringField(
"<dl><dt>CLIN 0003</dt> - <dd>Unclassified Cloud Support Package</dd></dl>",
translate("forms.financial.clin_0003_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_0003_description"),
filters=[number_to_int],
)
clin_1001 = NumberStringField(
"<dl><dt>CLIN 1001</dt> - <dd>Unclassified IaaS and PaaS Amount <br> OPTION PERIOD 1</dd></dl>",
translate("forms.financial.clin_1001_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_1001_description"),
filters=[number_to_int],
)
clin_1003 = NumberStringField(
"<dl><dt>CLIN 1003</dt> - <dd>Unclassified Cloud Support Package <br> OPTION PERIOD 1</dd></dl>",
translate("forms.financial.clin_1003_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_1003_description"),
filters=[number_to_int],
)
clin_2001 = NumberStringField(
"<dl><dt>CLIN 2001</dt> - <dd>Unclassified IaaS and PaaS Amount <br> OPTION PERIOD 2</dd></dl>",
translate("forms.financial.clin_2001_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_2001_description"),
filters=[number_to_int],
)
clin_2003 = NumberStringField(
"<dl><dt>CLIN 2003</dt> - <dd>Unclassified Cloud Support Package <br> OPTION PERIOD 2</dd></dl>",
translate("forms.financial.clin_2003_label"),
validators=[InputRequired()],
description="Review your task order document, the amounts for each CLIN must match exactly here",
description=translate("forms.financial.clin_2003_description"),
filters=[number_to_int],
)
pdf = FileField(
"Upload a copy of your Task Order",
translate("forms.financial.pdf_label"),
validators=[
FileAllowed(["pdf"], "Only PDF documents can be uploaded."),
FileAllowed(["pdf"], translate("forms.financial.pdf_allowed_description")),
InputRequired(),
],
render_kw={"required": False},
@@ -129,42 +132,60 @@ class TaskOrderForm(CacheableForm):
class RequestFinancialVerificationForm(CacheableForm):
uii_ids = NewlineListField(
"Unique Item Identifier (UII)s related to your application(s) if you already have them.",
description="If you have more than one UII, place each one on a new line.",
translate("forms.financial.uii_ids_label"),
description=translate("forms.financial.uii_ids_description"),
)
pe_id = StringField(
"Program Element Number",
description="PE numbers help the Department of Defense identify which offices' budgets are contributing towards this resource use. <br/><em>It should be 7 digits followed by 1-3 letters, and should have a zero as the first and third digits.</em>",
translate("forms.financial.pe_id_label"),
description=translate("forms.financial.pe_id_description"),
validators=[InputRequired()],
)
treasury_code = StringField(
"Program Treasury Code",
description="Program Treasury Code (or Appropriations Code) identifies resource types. <br/> <em>It should be a four digit or six digit number, optionally prefixed by one or more zeros.</em>",
translate("forms.financial.treasury_code_label"),
description=translate("forms.financial.treasury_code_description"),
validators=[InputRequired(), Regexp(TREASURY_CODE_REGEX)],
)
ba_code = StringField(
"Program Budget Activity (BA) Code",
description="BA Code is used to identify the purposes, projects, or types of activities financed by the appropriation fund. <br/><em>It should be two digits, followed by an optional letter.</em>",
translate("forms.financial.ba_code_label"),
description=translate("forms.financial.ba_code_description"),
validators=[InputRequired(), Regexp(BA_CODE_REGEX)],
)
fname_co = StringField("KO First Name", validators=[InputRequired()])
lname_co = StringField("KO Last Name", validators=[InputRequired()])
fname_co = StringField(
translate("forms.financial.fname_co_label"), validators=[InputRequired()]
)
lname_co = StringField(
translate("forms.financial.lname_co_label"), validators=[InputRequired()]
)
email_co = EmailField("KO Email", validators=[InputRequired(), Email()])
email_co = EmailField(
translate("forms.financial.email_co_label"),
validators=[InputRequired(), Email()],
)
office_co = StringField("KO Office", validators=[InputRequired()])
office_co = StringField(
translate("forms.financial.office_co_label"), validators=[InputRequired()]
)
fname_cor = StringField("COR First Name", validators=[InputRequired()])
fname_cor = StringField(
translate("forms.financial.fname_cor_label"), validators=[InputRequired()]
)
lname_cor = StringField("COR Last Name", validators=[InputRequired()])
lname_cor = StringField(
translate("forms.financial.lname_cor_label"), validators=[InputRequired()]
)
email_cor = EmailField("COR Email", validators=[InputRequired(), Email()])
email_cor = EmailField(
translate("forms.financial.email_cor_label"),
validators=[InputRequired(), Email()],
)
office_cor = StringField("COR Office", validators=[InputRequired()])
office_cor = StringField(
translate("forms.financial.office_cor_label"), validators=[InputRequired()]
)
def reset(self):
"""

View File

@@ -2,12 +2,13 @@ from wtforms.fields import TextAreaField
from wtforms.validators import InputRequired
from .forms import CacheableForm
from atst.utils.localization import translate
class InternalCommentForm(CacheableForm):
text = TextAreaField(
"CCPO Internal Notes",
translate("forms.internal_comment.text_label"),
default="",
description="Add comments or notes for internal CCPO reference and follow-up here. <strong>These comments <em>will not</em> be visible to the person making the JEDI request.</strong>",
description=translate("forms.internal_comment.text_description"),
validators=[InputRequired()],
)

View File

@@ -5,20 +5,30 @@ from wtforms.validators import Required, Email, Length
from atst.forms.validators import IsNumber
from atst.forms.fields import SelectField
from atst.utils.localization import translate
from .data import WORKSPACE_ROLES
class NewMemberForm(FlaskForm):
first_name = StringField(label="First Name", validators=[Required()])
last_name = StringField(label="Last Name", validators=[Required()])
email = EmailField("Email Address", validators=[Required(), Email()])
dod_id = StringField("DOD ID", validators=[Required(), Length(min=10), IsNumber()])
first_name = StringField(
label=translate("forms.new_member.first_name_label"), validators=[Required()]
)
last_name = StringField(
label=translate("forms.new_member.last_name_label"), validators=[Required()]
)
email = EmailField(
translate("forms.new_member.email_label"), validators=[Required(), Email()]
)
dod_id = StringField(
translate("forms.new_member.dod_id_label"),
validators=[Required(), Length(min=10), IsNumber()],
)
workspace_role = SelectField(
"Workspace Role",
translate("forms.new_member.workspace_role_label"),
choices=WORKSPACE_ROLES,
validators=[Required()],
default="",
description="The workspace role controls whether a member is permitted to organize a workspace into projects and environments, add members to this workspace, and view billing information.",
description=translate("forms.new_member.workspace_role_description"),
)

View File

@@ -14,6 +14,7 @@ from .data import (
)
from .validators import DateRange, IsNumber
from atst.domain.requests import Requests
from atst.utils.localization import translate
class DetailsOfUseForm(CacheableForm):
@@ -43,120 +44,126 @@ class DetailsOfUseForm(CacheableForm):
# Details of Use: General
dod_component = SelectField(
"DoD Component",
description="Identify the DoD component that is requesting access to the JEDI Cloud",
translate("forms.new_request.dod_component_label"),
description=translate("forms.new_request.dod_component_description"),
choices=SERVICE_BRANCHES,
validators=[InputRequired()],
)
jedi_usage = TextAreaField(
"JEDI Usage",
description="Your answer will help us provide tangible examples to DoD leadership how and why commercial cloud resources are accelerating the Department's missions",
translate("forms.new_request.jedi_usage_label"),
description=translate("forms.new_request.jedi_usage_description"),
validators=[InputRequired()],
)
# Details of Use: Cloud Readiness
num_software_systems = IntegerField(
"Number of Software Systems",
description="Estimate the number of software systems that will be supported by this JEDI Cloud access request",
translate("forms.new_request.num_software_systems_label"),
description=translate("forms.new_request.num_software_systems_description"),
)
jedi_migration = RadioField(
"JEDI Migration",
description="Are you using the JEDI Cloud to migrate existing systems?",
translate("forms.new_request.jedi_migration_label"),
description=translate("forms.new_request.jedi_migration_description"),
choices=[("yes", "Yes"), ("no", "No")],
default="",
)
rationalization_software_systems = RadioField(
description="Have you completed a “rationalization” of your software systems to move to the cloud?",
description=translate(
"forms.new_request.rationalization_software_systems_description"
),
choices=[("yes", "Yes"), ("no", "No"), ("In Progress", "In Progress")],
default="",
)
technical_support_team = RadioField(
description="Are you working with a technical support team experienced in cloud migrations?",
description=translate("forms.new_request.technical_support_team_description"),
choices=[("yes", "Yes"), ("no", "No")],
default="",
)
organization_providing_assistance = RadioField( # this needs to be updated to use checkboxes instead of radio
description="If you are receiving migration assistance, what is the type of organization providing assistance?",
description=translate(
"forms.new_request.organization_providing_assistance_description"
),
choices=ASSISTANCE_ORG_TYPES,
default="",
)
engineering_assessment = RadioField(
description="Have you completed an engineering assessment of your systems for cloud readiness?",
description=translate("forms.new_request.engineering_assessment_description"),
choices=[("yes", "Yes"), ("no", "No"), ("In Progress", "In Progress")],
default="",
)
data_transfers = SelectField(
description="How much data is being transferred to the cloud?",
description=translate("forms.new_request.data_transfers_description"),
choices=DATA_TRANSFER_AMOUNTS,
validators=[DataRequired()],
)
expected_completion_date = SelectField(
description="When do you expect to complete your migration to the JEDI Cloud?",
description=translate("forms.new_request.expected_completion_date_description"),
choices=COMPLETION_DATE_RANGES,
validators=[DataRequired()],
)
cloud_native = RadioField(
description="Are your software systems being developed cloud native?",
description=translate("forms.new_request.cloud_native_description"),
choices=[("yes", "Yes"), ("no", "No")],
default="",
)
# Details of Use: Financial Usage
estimated_monthly_spend = IntegerField(
"Estimated Monthly Spend",
description='Use the <a href="/jedi-csp-calculator" target="_blank" class="icon-link">JEDI CSP Calculator</a> to estimate your <b>monthly</b> cloud resource usage and enter the dollar amount below. Note these estimates are for initial approval only. After the request is approved, you will be asked to provide a valid Task Order number with specific CLIN amounts for cloud services.',
translate("forms.new_request.estimated_monthly_spend_label"),
description=translate("forms.new_request.estimated_monthly_spend_description"),
)
dollar_value = IntegerField(
"Total Spend",
description="What is your total expected budget for this JEDI Cloud Request?",
translate("forms.new_request.dollar_value_label"),
description=translate("forms.new_request.dollar_value_description"),
)
number_user_sessions = IntegerField(
description="How many user sessions do you expect on these systems each day?"
description=translate("forms.new_request.number_user_sessions_description")
)
average_daily_traffic = IntegerField(
"Average Daily Traffic (Number of Requests)",
description="What is the average daily traffic you expect the systems under this cloud contract to use?",
translate("forms.new_request.average_daily_traffic_label"),
description=translate("forms.new_request.average_daily_traffic_description"),
)
average_daily_traffic_gb = IntegerField(
"Average Daily Traffic (GB)",
description="What is the average daily traffic you expect the systems under this cloud contract to use?",
translate("forms.new_request.average_daily_traffic_gb_label"),
description=translate("forms.new_request.average_daily_traffic_gb_description"),
)
start_date = DateField(
description="When do you expect to start using the JEDI Cloud (not for billing purposes)?",
description=translate("forms.new_request.start_date_label"),
validators=[
InputRequired(),
DateRange(
lower_bound=pendulum.duration(days=1),
upper_bound=None,
message="Must be a date in the future.",
message=translate(
"forms.new_request.start_date_date_range_validation_message"
),
),
],
format="%m/%d/%Y",
)
name = StringField(
"Name Your Request",
description="This name serves as a reference for your initial request and the associated workspace that will be created once this request is approved. You may edit this name later.",
translate("forms.new_request.name_label"),
description=translate("forms.new_request.name_description"),
validators=[
InputRequired(),
Length(
min=4,
max=100,
message="Request names must be at least 4 and not more than 100 characters",
message=translate("forms.new_request.name_length_validation_message"),
),
],
)
@@ -187,21 +194,29 @@ class WorkspaceOwnerForm(CacheableForm):
return super().validate(*args, **kwargs)
am_poc = BooleanField(
"I am the Workspace Owner",
translate("forms.new_request.am_poc_label"),
default=False,
false_values=(False, "false", "False", "no", ""),
)
fname_poc = StringField("First Name", validators=[InputRequired()])
fname_poc = StringField(
translate("forms.new_request.fname_poc_label"), validators=[InputRequired()]
)
lname_poc = StringField("Last Name", validators=[InputRequired()])
lname_poc = StringField(
translate("forms.new_request.lname_poc_label"), validators=[InputRequired()]
)
email_poc = EmailField("Email Address", validators=[InputRequired(), Email()])
email_poc = EmailField(
translate("forms.new_request.email_poc_label"),
validators=[InputRequired(), Email()],
)
dodid_poc = StringField(
"DoD ID", validators=[InputRequired(), Length(min=10), IsNumber()]
translate("forms.new_request.dodid_poc_label"),
validators=[InputRequired(), Length(min=10), IsNumber()],
)
class ReviewAndSubmitForm(CacheableForm):
reviewed = BooleanField("I have reviewed this data and it is correct.")
reviewed = BooleanField(translate("forms.new_request.reviewed_label"))

View File

@@ -2,21 +2,34 @@ from flask_wtf import FlaskForm
from wtforms.fields import StringField, TextAreaField, FieldList
from wtforms.validators import Required
from atst.forms.validators import ListItemRequired, ListItemsUnique
from atst.utils.localization import translate
class ProjectForm(FlaskForm):
name = StringField(label="Project Name", validators=[Required()])
description = TextAreaField(label="Description", validators=[Required()])
name = StringField(
label=translate("forms.project.name_label"), validators=[Required()]
)
description = TextAreaField(
label=translate("forms.project.description_label"), validators=[Required()]
)
class NewProjectForm(ProjectForm):
EMPTY_ENVIRONMENT_NAMES = ["", None]
environment_names = FieldList(
StringField(label="Environment Name"),
StringField(label=translate("forms.project.environment_names_label")),
validators=[
ListItemRequired(message="Provide at least one environment name."),
ListItemsUnique(message="Environment names must be unique."),
ListItemRequired(
message=translate(
"forms.project.environment_names_required_validation_message"
)
),
ListItemsUnique(
message=translate(
"forms.project.environment_names_unique_validation_message"
)
),
],
)

View File

@@ -2,6 +2,7 @@ import re
from wtforms.validators import ValidationError
import pendulum
from datetime import datetime
from atst.utils.localization import translate
def DateRange(lower_bound=None, upper_bound=None, message=None):
@@ -27,7 +28,7 @@ def DateRange(lower_bound=None, upper_bound=None, message=None):
return _date_range
def IsNumber(message="Please enter a valid number."):
def IsNumber(message=translate("forms.validators.is_number_message")):
def _is_number(form, field):
try:
int(field.data)
@@ -37,7 +38,7 @@ def IsNumber(message="Please enter a valid number."):
return _is_number
def PhoneNumber(message="Please enter a valid 5 or 10 digit phone number."):
def PhoneNumber(message=translate("forms.validators.phone_number_message")):
def _is_phone_number(form, field):
digits = re.sub(r"\D", "", field.data)
if len(digits) not in [5, 10]:
@@ -50,9 +51,7 @@ def PhoneNumber(message="Please enter a valid 5 or 10 digit phone number."):
return _is_phone_number
def Name(
message="This field accepts letters, numbers, commas, apostrophes, hyphens, and periods."
):
def Name(message=translate("forms.validators.name_message")):
def _name(form, field):
match = re.match(r"[\w \,\.\'\-]+", field.data)
if not match or match.group() != field.data:
@@ -61,7 +60,10 @@ def Name(
return _name
def ListItemRequired(message="Please provide at least one.", empty_values=("", None)):
def ListItemRequired(
message=translate("forms.validators.list_item_required_message"),
empty_values=("", None),
):
def _list_item_required(form, field):
non_empty_values = [v for v in field.data if v not in empty_values]
if len(non_empty_values) == 0:
@@ -70,7 +72,7 @@ def ListItemRequired(message="Please provide at least one.", empty_values=("", N
return _list_item_required
def ListItemsUnique(message="Items must be unique"):
def ListItemsUnique(message=translate("forms.validators.list_items_unique_message")):
def _list_items_unique(form, field):
if len(field.data) > len(set(field.data)):
raise ValidationError(message)

View File

@@ -2,16 +2,17 @@ from wtforms.fields import StringField
from wtforms.validators import Length
from .forms import CacheableForm
from atst.utils.localization import translate
class WorkspaceForm(CacheableForm):
name = StringField(
"Workspace Name",
translate("forms.workspace.name_label"),
validators=[
Length(
min=4,
max=100,
message="Workspace names must be at least 4 and not more than 50 characters",
message=translate("forms.workspace.name_length_validation_message"),
)
],
)

View File

@@ -0,0 +1,35 @@
import yaml
import os
from functools import lru_cache
from atst.utils import getattr_path
ENV = os.getenv("FLASK_ENV", "dev")
class LocalizationInvalidKeyError(Exception):
def __init__(self, key, variables):
self.key = key
self.variables = variables
def __str__(self):
return "Requested {key} and variables {variables} with but an error occured".format(
key=self.key, variables=self.variables
)
localizations_cache_size = 1 if ENV == "dev" else None
@lru_cache(maxsize=localizations_cache_size)
def load_cached_translations_file(file_name):
return open(file_name).read()
def translate(key, variables={}):
translations = yaml.safe_load(load_cached_translations_file("translations.yaml"))
value = getattr_path(translations, key)
if value == None:
raise LocalizationInvalidKeyError(key, variables)
return value.format(**variables).replace("\n", "")