Technical Articles
Build an English Premier League app with SAP Cloud Application Programming Model – part 2 reuse, localization, annotations
part 2 reuse, localization, annotations
part 3 part 3 build a UI and deploy to Cloud Foundry
part 4 deploy to cloud foundry as multi-target app
Once I finished part 1 of the series, I thought that if I want to build a bigger and more complex application with SAP Cloud Application Programming Model, maybe I should take reference of the itelo, product catalog and foundation and reorganize the project code a bit to make it more reusable and less messy before I heading up towards the UI part.
One more thing, we will have a look at how to use the “CodeList” from @sap/cds/common package.
The Plan
I am going to do some restructure of the project files, accrording to the cap development best practices, then experiment a bit on localization. Lastly I will put some annotations to make the preview screen of the matches and teams more beautiful.
Prepare
1. Remember to do an npm update and npm install to bring down the latest cds version and other dependencies.
>cds -v
@sap/cds: 3.18.1
@sap/cds-compiler: 1.19.2
@sap/cds-messaging: 1.2.1
@sap/cds-ql: 1.19.2
@sap/cds-reflect: 2.8.0
@sap/cds-rest: 1.2.0
@sap/cds-services: 1.19.1
@sap/generator-cds: 2.9.0
Get Started
Change on the data model
1. Here is the new db/data-model.cds. I have created a new “type” called “Team”, then I can reuse the type for both “homeTeam” and “awayTeam”. “Teams” entity is reusing the “CodeList” provided by @sap/cds/common package.
namespace com.epl;
using { managed, cuid, sap.common.CodeList } from '@sap/cds/common';
type Team : Association to Teams;
entity Teams : managed, CodeList {
key ID : Integer @(title : '{i18n>homeTeam}');
}
entity Matches: cuid, managed {
matchDate: Date;
homeTeam : Team;
awayTeam: Team;
homeTeamScore: Integer;
awayTeamScore: Integer;
}
No Change on the service catalog
namespace com.epl;
using com.epl as db from '../db/data-model';
service CatalogService {
@readonly
entity Teams as projection on db.Teams;
@readonly
entity Matches as select from db.Matches
order by matchDate desc;
}
Index.cds file
1. Best practice guide mentioned an index.cds on the project root is recommended to modularize cds projects. I created a new index.cds file like this
namespace com.epl;
using from './db/data-model';
using from './srv/cat-service';
using from './srv/Matches-annotations';
using from './srv/Teams-annotations';
2. Note that there are two new annotation files included in here. They will be addressing these files later in the post. In this way, we can include multiple data model files, catalog service files (which I am planning to do in the future posts) and we can easily include/exclude different modules.
3. Make sure this entry is updated in the package.json
"files": [
"srv",
"db",
"index.cds"
],
Annotations
1. I like to seperate annotations based on entities. It will make the project easy to maintain once it is growing bigger.
2. Matches-annotation.cds. See we created some filters with the code list (value help) just by putting annotations.
using com.epl.CatalogService from './cat-service';
annotate CatalogService.Matches with @(
UI:{
Identification: [{ Value: '{i18n>matches}' }],
SelectionFields: [ 'matchDate','homeTeam_ID','awayTeam_ID' ],
LineItem: [
{ Value: matchDate, Label: '{i18n>matchDate}' },
{ Value: homeTeam.name, Label: '{i18n>homeTeam}' },
{ Value: homeTeamScore },
{ Value: ':' },
{ Value: awayTeamScore },
{ Value: awayTeam.name, Label: '{i18n>awayTeam}' }
]
}
){
matchDate @title:'{i18n>matchDate}';
homeTeam @(
Common: {
Label: '{i18n>homeTeam}',
ValueList: {
Label: '{i18n>homeTeam}',
CollectionPath: 'Teams',
Parameters:[
{ $Type:'Common.ValueListParameterInOut', LocalDataProperty: 'homeTeam_ID', ValueListProperty:'ID' },
{ $Type:'Common.ValueListParameterDisplayOnly', ValueListProperty:'name' },
]
}
}
);
awayTeam @(
Common: {
Label: '{i18n>awayTeam}'
}
);
};
3. Teams-annotations.cds is coving the annotations for the “Teams” entity. There is an annotation @cds.odata.valuelist which can also be used to “mark” an entity type as codelist (value list, value help or whatever…), if you do not want to borrow it from the out-of-box “sap.common.codelist”.
using com.epl.CatalogService from './cat-service';
annotate CatalogService.Teams with @(
UI: {
Identification : [name],
SelectionFields: [name],
LineItem: [
{ Value: ID, Label: '{i18n>ID}' },
{ Value: name, Label: '{i18n>name}' }
]
}
){
ID @title:'{i18n>ID}' @UI.HiddenFilter;
name @title:'{i18n>name}';
}
//annotate CatalogService.Teams with @cds.odata.valuelist;
A Quick Test
1. We do a quick test by
cds deploy && cds watch .
2. Teams preview
3. Matches preview
4. Choose the Home Team or Away Team filter on the top. The Code List popped up.
5. Live update on the filter. Looks pretty good.
Localization
1. create a file _i18n/i18n_zh.properties. Obviously I already created _i18n/i18n.properties file for English (default language).
matches=比赛
matchDate=比赛日期
homeTeam=主队
awayTeam=客队
name=队名
2. Go to the url with the sap-language parameter
http://localhost:4004/$fiori-preview/?service=com.epl.CatalogService&entity=Matches&sap-language=zh_CN
3. Check the results. Awesome!!!
4. What about the team names, I want to display them in Chinese too. Let’s try to load some data into com.epl-Teams_text.csv.
ID,name,locale
1,阿森纳,zh
2,阿斯顿维拉,zh
3,伯恩茅斯,zh
4,布莱顿,zh
.....
5. Unfortunately it does not work. The cause is that cds only creates localized view on de and fr language in sqlite db. A possible bug we found?
6. To prove that I loaded the csv as de (German).
ID,name,locale
1,阿森纳,de
2,阿斯顿维拉,de
3,伯恩茅斯,de
4,布莱顿,de
.....
7. Check the results in
http://localhost:4004/$fiori-preview/?service=com.epl.CatalogService&entity=Teams&sap-language=de_DE
Thanks Walldorf we got it working. 🙂
Next Step
I will official dive into the UI part, as I think we have played enough with the fiori preview.
Stay tuned. #epl-app
very cool demo project! specifically like the mandarin localization, nothing more challenging for internationalization features than this 🙂
how about adding it to https://github.com/sapmentors/cap-community/tree/master/examples?
you could then even file an issue in the same repo about the "de"- and "fr"-only loading of texts 🙂 the #CAP team monitors the issue space in above repo