S3TemplateEngine is a lightweight template engine for AWS serverless computing, helping you create AWS S3 / AWS Cloudfront hosted websites. It optionally integrates Webiny.
- Motivation
- Concept
- Support
- Installation
- Useage
- Commands
- Optional - automated testing with JEST
- Optional - page variations - e.g. website and web-app
- Optional - Multi language pages
- Optional - Webiny integration
- Optional - Webiny multi language pages
AWS S3 and AWS Cloudfront offer a great platform to publish websites and web apps at a low cost. However, you need to create static HTML files elsewhere, and getting everything up and running can be a pain without a decent CMS.
This project is for you, if you want to manually create HTML and benefit from low-cost serverless computing but still want to:
- Reuse code snippets (like header or navigation)
- Use a CMS for updating your content
- Automatically create pages dynamically (like an individual page for each article you put in a system, rather than an SEO unfriendly AJAX load of content on a generic page)
- Have a pipeline that optimizes/minifies your code output
If you want to support this project by buying me a tea (I'm not into coffee ;-) ), feel free: https://ko-fi.com/hokcomics
If you need support, found a bug or want to donate a pull request, feel free to contact me via github.
S3TemplateEngine uses serverless technologies (S3, Lambda, DynamoDB, Cloudformation) to provide a straightforward but powerful template language.
All you have to do is follow the installation paragraph, and you can write your HTML-based templates, put them into a specific S3 bucket and see the magic happen.
Download the github repository.
Use your preferred way to pull the project, or (if you are not that experienced with git), do it manually:
-
Go to the project github page ( https://github.com/HOKComics/S3TemplateEngine )
-
Right Click on "S3TemplateEngine.json" and choose "save link as"
-
Download the file ( Hint: this file is refered as "S3TemaplateEngine.json" later on )
-
Click on "S3"
-
Right Click on the file inside and choose "save link as"
-
Download the file ( Hint: this file is refered as "* files inside the s3 folder*" later on )
Create an S3 bucket and upload the content of the folder "s3" (multiple zip files) into it.
- Navigate to your S3 console. At the time this document was created, the link is https://s3.console.aws.amazon.com/s3/buckets
- Choose your region in the top right of the window.
- Click on "Create bucket"
- Enter a name for your bucket, like "mywebsite-temp" ( Hint: this name is refered as "S3LambdaBucket" later on )
- Click on "Create bucket"
- Click on the "S3LambdaBucket" to open it
- Click on Upload
- Click on "Add files" and choose the files inside the "s3" folder you downloaded from GitHub earlier ( Hint: just the files, NOT the folder )
- Click on Upload
Connect your domain in AWS Route53 and create an SSL certificate with the AWS Certificate Manager ("www." and "" ).
- This part is highly individual and not directly connected to the S3TemplateEngine project. To learn about this topic, refer to the AWS documentation ( https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring.html )
- It must cover at least no-subdomain and www-subdomain (e. g. "mydomain.com" and "www.mydomain.com")
Execute the "S3TemaplateEngine.json" in CloudFormation.
- Cretae an AWS account or sign in into an existing one
- In the AWS console, make sure you are on target region (S3TemplateEngine is currently only working within a single region)
- go to "CloudFormation"
- Click on "Create Stack"
- Select "Template is ready" and "Upload a template file"
- Click on "choose file" and select "S3TemaplateEngine.json"
- Click on "Next"
- Fill out Stack Name and Parameters
- Click "Next"
- Check "I acknowledge that AWS CloudFormation might create IAM resources with custom names."
- Click "Create Stack"
Connect your Route53 domain to the CloundFront that was created.
- In the AWS console, open Route53
- Navigate to your hosted zone
- Generate record "empty" "A"
- Click on "Create record"
- leave the box before your doamin name empty
- choose "A" as record type
- Check "Alias" and choose "Alias to CloudFront distribution"
- Choose the distribution that was created earlier (by CloudFormation)
- Click "Add another record" and repeat the same for "empty" "AAAA"
- Click "Add another record" and repeat the same for "www" "A"
- Click "Add another record" and repeat the same for "www" "AAAA"
- Click on Create records
Delete the S3 bucket you created in the second step.
- Navigate to your S3 console. At the time this document was created, the link is https://s3.console.aws.amazon.com/s3/buckets
- Click on the radiob utton in front of the "S3LambdaBucket" you created in the second step of this manual, to select it
- Click on "Empty"
- Write "permanently delete" in the verification tetx field and click "Empty"
- Click on "Exit"
- Click on "Delete"
- Write the name of your "S3LambdaBucket" in the verification tetx field and click "Delete bucket"
Just put your template (usual website files, html with the additional commands shown below) in the "prod-website-code-<your page name>" s3 bucket. The system will behave as follows:
Content from the following folders will be synced (copied or deleted) to the output S3 bucket:
- files/ (usually used for downloads like pdfs)
- gfx/ (usually used for visuals used on the website and css files)
- js/ (used for javascript files)
Content from the following folders will be processed with the commands shown below:
- website/ (will be the root of the output folder)
- The following files are madatory:
- index.html (your main page)
- 404.html (your error page)
- The following files are madatory:
- part/
Other folders and files int the root will be ignored
Inside the files you put into "website/" and "part/", you can use the following tags:
<part> - Reusing code from other files
Renders a certain code only, if a condition is met. Currently the only available condition is the environment. This is handy, if you want to have different "robots" meta tags for your produciton environment, than for dev and stage.
<part>*name*</part>
Whereas name is a filename or path/filename inside the "part/" directory.
<head>
<part>head.part</part>
</head>
<if> - Only render code, if you are in a certain environment
Replaces the command with the content from another file. This is handy, if you want to reuse HTML headers or navigation.
<part>*json*</part>
Whereas json is a is a json object with the following attributes:
{
"env": "match the current environment dev|stage|prod",
"file": "match the rendered filename e.g. index.html",
"not": true|false - if true invert result of other machtes,
"template": "an HTML template, that will either appear or not appear"
}
Whereas env, file and not are optional (but the whole command only makes sense, if you use at least one of them).
<if>{
"env": "dev",
"template": "<meta name='robots' content='noindex'><meta name='googlebot' content='noindex'>"
}</if>
<if>{
"env": "stage",
"template": "<meta name='robots' content='noindex'><meta name='googlebot' content='noindex'>"
}</if>
<if>{
"env": "prod",
"template": "<meta name='robots' content='all'><meta name='googlebot' content='all'>"
}</if>
<fileattribute> - Inserts file attributs (also Webiny items values, based on dbmultifile loop created files)
Replaces the <fileattribute>-command with the current filename. Handy for generation of canonical tags.
Also works inside a <dbmultifile>-command:
<fileattribute>filename</fileattribute>
Currently filename is the only command available.
<fileattribute>filename</fileattribute>
If you want to test the output source code with JEST during development, this is a littly tricky, as you will want to dio the in a "jsdom" environment, whereas the S3TE needs a node environment. Here's what to do:
Preparation
- Copy the "test example/S3TE" folder and its contents in the "test" folder of your project
Write your test
Have a look at "test example/index.test.js" it uses jest axe to test the accessibility of the source code generated by S3TE. Just write your own tests like the one outlined there and use the sHTML (s stands for "string") variable to do your checks. The magic is started here in the "beforeAll" block.
If you want to host multiple pages with similar content and/or domains but different code, S3 Template Engine has your back. A common use case is having a website and a web-app with a slightly different domain (e.g. app.your-domain.com), same CMS/Webiny objects to render and different hmtl/CSS/JavaScript code.
In this setup you'll have a seperate code input bucket for each variation and of course a unique cloud front distribution for each.
Preparation
- If not already done, Install S3TemplateEngine, as described in the Installation paragraph.
Execute the "S3TemaplateEngineAdditionalVariation.json" in CloudFormation.
- Cretae an AWS account or sign in into an existing one
- In the AWS console, make sure you are on target region (S3TemplateEngine is currently only working within a single region)
- go to "CloudFormation"
- Click on "Create Stack"
- Select "Template is ready" and "Upload a template file"
- Click on "choose file" and select "S3TemaplateEngineAdditionalVariation.json"
- Click on "Next"
- Fill out Stack Name and Parameters Be aware, that the parameters Environment and WebsiteName have to be exactly the same parameters you used when installing S3TemaplateEngine - Website URL may differ
- Click "Next"
- Check "I acknowledge that AWS CloudFormation might create IAM resources with custom names."
- Click "Create Stack"
Connect your Route53 domain to the CloundFront that was created.
- In the AWS console, open Route53
- Navigate to your hosted zone
- Generate record "empty" "A"
- Click on "Create record"
- leave the box before your doamin name empty
- choose "A" as record type
- Check "Alias" and choose "Alias to CloudFront distribution"
- Choose the distribution that was created earlier (by CloudFormation)
- Click "Add another record" and repeat the same for "empty" "AAAA"
- Click "Add another record" and repeat the same for "www" "A"
- Click "Add another record" and repeat the same for "www" "AAAA"
- Click on Create records
Tell your Lambda function 'HOK_move_file' about the buckets you created.
- In the AWS console, open Lambda
- Find "_HOK_move_file" and click on the linked function name to open function editing
- Navigate to "Configuration" and "Environment variables", there click on edit
- Edit the value of the key "config", by adding the new variation buckets to the array
If you use multiple different variations of your content (e.g. an "app." besides a "www."), you need to add one language array for each content.
{
"website":[
{"<countrycode>":"<s3 bucket name>"},
...
],
"<variation name>":[
{"<countrycode>":"<s3 bucket name>"},
...
],
...
}
If you use multiple different variations of your content (e.g. an "app." besides a "www."), you need to add one language array for each content.
{
"website":[
{"<countrycode>":"<s3 bucket name>"},
{"<countrycode>":"<s3 bucket name for new lang>"},
...
],
"<variation name>":[
{"<countrycode>":"<s3 bucket name>"},
{"<countrycode>":"<s3 bucket name for new lang>"},
...
],
...
}
e.g.
{
"website":[
{
"en":
{
"bucket":"prod-website-myurl",
"baseurl":"mywebsite.com"
}
},
{
"de":{
"bucket":"prod-website-myurl-de",
"baseurl":"mywebsite.de"
}
}
],
"app":[
{
"en":
{
"bucket":"prod-app-myurl",
"baseurl":"mywebsite.com"
}
},
{
"de":{
"bucket":"prod-app-myurl-de",
"baseurl":"mywebsite.de"
}
}
]
}
It has to be entered as one liner, so it will become
{ "website":[ { "en": { "bucket":"prod-website-myurl", "baseurl":"mywebsite.com" } }, { "de":{ "bucket":"prod-website-myurl-de", "baseurl":"mywebsite.de" } } ], "app":[ { "en": { "bucket":"prod-app-myurl", "baseurl":"mywebsite.com" } }, { "de":{ "bucket":"prod-app-myurl-de", "baseurl":"mywebsite.de" } } ] }
Tell your Lambda function 'HOK_render_html_files' about the buckets you created.
- In the AWS console, open Lambda
- Find "_HOK_render_html_files" and click on the linked function name to open function editing
- Navigate to "Configuration" and "Environment variables", there click on edit
- Edit the value of the key "config" as described below and click on "save"
You need to create a small JSON with your data and then enter it into the "value" field without any line breaks. It's teh same you used for 'HOK_move_file' in the last step.
The use of multiple languages on your page is optional. However, if you want to use them, you'll need some additional preperation steps. After that you can utilize the languag specific commands, shown below. The idea of this multi language implementation is, that you'll have a different CloudFront distribution per page. This will allow you full control, what type of URL you use:
Example 1 | Example 2 | Example 3 | |
---|---|---|---|
EN | "mydomain.com" | "en.mydomain.com" | "mydomain.com/en" |
DE | "mydomain.de" | "de.mydomain.com" | "mydomain.com/de" |
Preparation
- If not already done, Install S3TemplateEngine, as described in the Installation paragraph.
Execute the "S3TemaplateEngineAdditionalLanguage.json" in CloudFormation.
- Cretae an AWS account or sign in into an existing one
- In the AWS console, make sure you are on target region (S3TemplateEngine is currently only working within a single region)
- go to "CloudFormation"
- Click on "Create Stack"
- Select "Template is ready" and "Upload a template file"
- Click on "choose file" and select "S3TemaplateEngineAdditionalLanguage.json"
- Click on "Next"
- Fill out Stack Name and Parameters Be aware, that the parameters Environment and WebsiteName have to be exactly the same parameters you used when installing S3TemaplateEngine - Website URL may differ
- Click "Next"
- Check "I acknowledge that AWS CloudFormation might create IAM resources with custom names."
- Click "Create Stack"
Connect your Route53 domain to the CloundFront that was created.
- In the AWS console, open Route53
- Navigate to your hosted zone
- Generate record "empty" "A"
- Click on "Create record"
- leave the box before your doamin name empty
- choose "A" as record type
- Check "Alias" and choose "Alias to CloudFront distribution"
- Choose the distribution that was created earlier (by CloudFormation)
- Click "Add another record" and repeat the same for "empty" "AAAA"
- Click "Add another record" and repeat the same for "www" "A"
- Click "Add another record" and repeat the same for "www" "AAAA"
- Click on Create records
Tell your Lambda function 'HOK_move_file' about the buckets you created.
- In the AWS console, open Lambda
- Find "_HOK_move_file" and click on the linked function name to open function editing
- Navigate to "Configuration" and "Environment variables", there click on edit
- Edit the value of the key "config", by adding the new variation buckets to the array
If you use multiple different variations of your content (e.g. an "app." besides a "www."), you need to add one language array for each content.
{
"website":[
{"<countrycode>":"<s3 bucket name>"},
{"<countrycode>":"<s3 bucket name for new lang>"},
...
]
}
If you use multiple different variations of your content (e.g. an "app." besides a "www."), you need to add one language array for each content.
{
"website":[
{"<countrycode>":"<s3 bucket name>"},
{"<countrycode>":"<s3 bucket name for new lang>"},
...
],
"<variation name>":[
{"<countrycode>":"<s3 bucket name>"},
{"<countrycode>":"<s3 bucket name for new lang>"},
...
],
...
}
e.g.
{
"website":[
{
"en":
{
"bucket":"prod-website-myurl",
"baseurl":"mywebsite.com"
}
},
{
"de":{
"bucket":"prod-website-myurl-de",
"baseurl":"mywebsite.de"
}
}
],
"app":[
{
"en":
{
"bucket":"prod-app-myurl",
"baseurl":"mywebsite.com"
}
},
{
"de":{
"bucket":"prod-app-myurl-de",
"baseurl":"mywebsite.de"
}
}
]
}
It has to be entered as one liner, so it will become
{ "website":[ { "en": { "bucket":"prod-website-myurl", "baseurl":"mywebsite.com" } }, { "de":{ "bucket":"prod-website-myurl-de", "baseurl":"mywebsite.de" } } ], "app":[ { "en": { "bucket":"prod-app-myurl", "baseurl":"mywebsite.com" } }, { "de":{ "bucket":"prod-app-myurl-de", "baseurl":"mywebsite.de" } } ] }
Tell your Lambda function 'HOK_render_html_files' about the buckets you created.
- In the AWS console, open Lambda
- Find "_HOK_render_html_files" and click on the linked function name to open function editing
- Navigate to "Configuration" and "Environment variables", there click on edit
- Edit the value of the key "config" as described below and click on "save"
You need to create a small JSON with your data and then enter it into the "value" field without any line breaks. It's teh same you used for 'HOK_move_file' in the last step.
Inside the files you put into "website/" and "part/", you can use the following tags:
<lang> - Printing the current pages language
### Action Renders the current language. Handy for language switchers and meta data. ### Syntax ```html *command* ``` Whereas *command* is 2 for a 2 digit lang code (like "en", "de", "fr", ...).Whereas *command* is baseurl for printing the language specific baseurl you defined in the set-up step. ### Example ```html ... ```
<switchlang> - Providing different content for multiple languages
### Action Renders language specific content (e.g. hardcoded text). ### Syntax ```html <*lang*>*content*<*/lang*> ... ``` Whereas *lang* is the 2 digit lang code (like "en", "de", "fr", ...), and *content* is the content for this lang code. ### Example ```htmlDein ultimatives Website Werkzeug Your ultimate website tool
```S3TemplateEngine supports Webiny as an editors interface. Webiny ( https://www.webiny.com/ ), an open source serverless CMS ranging from a free version up to enterprise grade, also uses serverless technologies from AWS. We integrate it without any code change in Webiny, by accessing the published items on database level. So you it goes with a vanilla installation as well as with a highly cusomized one.
All you have to do is to follow the installation paragraph, and you can use your Webiny generated content in your HTML-based templates.
Intall S3TemplateEngine.
- Install S3TemplateEngine, as described in the Installation paragraph.
Intall Webiny.
- Install Webiny, as described in the Webiny documentation. ( https://www.webiny.com/docs/get-started/install-webiny )
Prepare Webiny.
- Log in and create the models you need in the Webiny backend. The names of these models will be needed for the following steps.
- Hint: If you want to add or remove a model after installation, you can do so by manually editing the of the "relevant_webiny_models" environment variable of the "_HOK_transfer_published_item" lambda function.
- In addition, create the following two models:
- model name "staticCodeContent", containing
- a text field called "contentid" with the restriction "unique"
- a long text field "content"
- This model will be used for specific content you only have one instance of, that is source code, like a tracking pixel
- It will be available via it's "contentid", if you want to hand these over to editors, I recommend prepareing the available contentid values as predefined value
- model name "staticContent", containing
- a text field called "contentid" with the restriction "unique"
- a rich text field "content"
- This one will be used for specific content you only have one instance of, like the "about us" page
- It will be available via it's "contentid", if you want to hand these over to editors, I recommend prepareing the available contentid values as predefined value
- model name "staticCodeContent", containing
Download the github repository.
If you pulled the project in the S3TemplateEngine installation: fine, else do it manually:-
Go to the project github page ( https://github.com/HOKComics/S3TemplateEngine )
-
Right Click on "S3TemplateEngineWebiny.json" and choose "save link as"
-
Download the file ( Hint: this file is refered as "S3TemaplateEngineWebiny.json" later on )
-
Click on "s3Webiny"
-
Right Click on the file inside and choose "save link as"
-
Download the file ( Hint: this file is refered as "* files inside the s3Webiny folder*" later on )
Create an S3 bucket and upload the content of the folder "s3Webiny" (multiple zip files) into it.
- Navigate to your S3 console. At the time this document was created, the link is https://s3.console.aws.amazon.com/s3/buckets
- Choose your region in the top right of the window.
- Click on "Create bucket"
- Enter a name for your bucket, like "mywebsite-temp" ( Hint: this name is refered as "S3LambdaBucket" later on )
- Click on "Create bucket"
- Click on the "S3LambdaBucket" to open it
- Click on Upload
- Click on "Add files" and choose the files inside the "s3Webiny" folder you downloaded from GitHub earlier ( Hint: just the files, NOT the folder )
- Click on Upload
Execute the "S3TemaplateEngineWebiny.json" in CloudFormation.
- Cretae an AWS account or sign in into an existing one
- In the AWS console, make sure you are on target region (S3TemplateEngine is currently only working within a single region)
- go to "CloudFormation"
- Click on "Create Stack"
- Select "Template is ready" and "Upload a template file"
- Click on "choose file" and select "S3TemaplateEngineWebiny.json"
- Click on "Next"
- Fill out Stack Name and Parameters Be aware, that the parameters Environment and WebsiteName have to be exactly the same parameters you used when installing S3TemaplateEngine
- Click "Next"
- Check "I acknowledge that AWS CloudFormation might create IAM resources with custom names."
- Click "Create Stack"
Connect the DynamoDB stream of your webiny installation with the receiving lambda function of S3TemplateEngine.
- Navigate to your DynamoDB console. At the time this document was created, the link is https://console.aws.amazon.com/dynamodbv2/home
- Make sure you are in the correct region
- Clik on "tables"
- Click on your Webiny table (usually it's named "webiny-<7 digit code>")
- In “Export and Streams” -> “DynamoDB stream details” click on "Enable"
- Choose “New and old images” and click on “Enable stream”
- In “DynamoDB stream details” click on “Create trigger”
- Choose “PROD_HOK_transfer_published_item” (or “DEV_HOK_transfer_published_item” or similar, depending on your enviroment). Choose a Batch size of 1 and click “Create trigger”
Connect the DynamoDB stream of your content mirror tables with the receiving lambda function of S3TemplateEngine.
- Navigate to your DynamoDB console. At the time this document was created, the link is https://console.aws.amazon.com/dynamodbv2/home
- Make sure you are in the correct region
- Clik on "tables"
- Click on your Webiny table (usually it's named "PROD_WebsiteContentFromWebiny")
- In “DynamoDB stream details” click on “Create trigger”
- Choose “PROD_HOK_render_html_files” (or “DEV_HOK_render_html_files” or similar, depending on your enviroment). Choose a Batch size of 1 and click “Create trigger”
Delete the S3 bucket you created in the second step.
- Navigate to your S3 console. At the time this document was created, the link is https://s3.console.aws.amazon.com/s3/buckets
- Click on the radiob utton in front of the "S3LambdaBucket" you created in the second step of this manual, to select it
- Click on "Empty"
- Write "permanently delete" in the verification tetx field and click "Empty"
- Click on "Exit"
- Click on "Delete"
- Write the name of your "S3LambdaBucket" in the verification tetx field and click "Delete bucket"
Inside the files you put into "website/" and "part/", you can use the following tags:
<dbpart> - Inserting code or content maintained in Webiny
Replaces the command with the content from an Webiny maintained element. This is handy, if you want to give an editor access to static elements like a privacy statement or a tracking tag.
<dbpart>*name*</dbpart>
Whereas name is the "contentid" of a Webiny "Static Contents" or "Static Code Contents" element.
<body>
<dbpart>impressum</dbpart>
</body>
<dbmulti> - Inserting multiple Webiny items in one file
Replaces the command with a defined HTML template multiple times. Exactly once for each entry in the published Webiny content, matching the filter criteria. Handy for cretaing an overview page of articles.
<dbmulti>*json*</dbmulti>
Whereas json is a json object with the following attributes, attribute "limit" is optional:
{
"filter":[
{"AttributeName":{"DynamoDBType":"AttributeContent"}},
...
],
"filtertype": 'contains', if the query checks a multi select webiny entry
"limit": max number of elements to return,
"template":"an HTML template, that will probably contain <dbitem> elements"
}
Hint: You can sort entries by adding a number field named "order" to your Webiny model. After that edit your entries: smaller numbers come first, stuff with empty "order" fields are rendered at the end.
<dbmulti>{
"filter":[{"forWebsite":{"BOOL":true}}],
"limit":3,
"template":"<a href='artikeldetail-<dbitem>id</dbitem>.html'><h2><dbitem>headline</dbitem></h2><div class='content'><dbitem>readingtime</dbitem> min</div></a>"
}</dbmulti>
<dbmultifile> - Create a file for each Webiny item matching a filter
Creates multiple files out of one template file, by using one unqiue database attribute as suffix to the created filenames. Handy for generating individual pages for articles.
Must be first line of the tmeplate frile (even before <!Doctype html>)
<dbmultifile>*json*</dbmultifile>
Whereas json is a json object with the following attributes:
{
"filenamesuffix":"Dynamo DB field (muust be unique)",
"filter":[
{"AttributeName":{"DynamoDBType":"AttributeContent"}},
...
]
}
Whereas fieldname is the name of an attribute (column) from the DynamoDB
<dbmultifile>{
"filenamesuffix":"id",
"filter":[
{"__typename":{"S":"artikel"}}
]
}</dbmultifile>
<dbitem> - Inserts Webiny items values (used inside a dbmulti or dbmultifile loop)
Inside a <dbmulti>-command or <dbmultifile>-command: Replaces the <dbitem>-command with the content of a Webiny field of the current element.
<dbitem>*fieldname*</dbitem>
Whereas fieldname is the name of an attribute (column) from the DynamoDB.
<dbitem>headline</dbitem>
S3TemplateEngine differs from the standard Webiny way to implement multi language by intention.
Webiny usually allows you to define different data models for each language. This has some use cases and you can tweak S3TemplateEngine to work with this as well. (If you want to do this, please contact me: it has been done before, but it is a lillte more complicated and not part of the open source project.) But I consider these usecases as edge cases, so I decided to go a different way with S3TemplateEngine.
S3TemplateEngine works differently I strongly belive, that the best user experience for content editors is having the different locales side by side. Therefore we'll use ONE Webiny locale and one data model, inserting different fields for the different languages.
Intall S3TemplateEngine, Multi Language and Webiny.
- Install S3TemplateEngine, as described in the Installation paragraph.
- Install S3TemplateEngine multi language extension, as described in the Set-Up op multi language pages paragraph.
- Install S3TemplateEngine Webiny extension, as described in the Installation of optional Webiny extension paragraph.
Add fields for you additonal locales in all data models.
- Go to your Webiny admin interface
- Navigate to Modles -> staticContent and click the pen to edit the model You'll see a field "contentid" that's the key for your data item. And a field "content", that is the fallback content of your item. It will be rendered every time no language specific field is part of the model. For the most of us, it will be benificial to here put the english content.
- To add a language, add another field like "content" (in this case a "rich text input" field) and name it "content". e.g. "contentde". I'm talking about the "Field ID" here, not the label. Exyample: You can lable the content field with English and the contentde field with German, if oyu want. You can add as many languages as you like, but be aware, that you'll need to fill these fields for all content elements. An empty field will result in an empty string. The fallback functionality just works, if a whole language is not set up in the model.
- Click on "Save"
- Repeat this for "staticCodeContent" and all custom models you created.