How do I get both auto-localized select list enums AND datatables in ABP Framework (abp.io) - localization

In the ABP framework, the tutorial for version 5.1 says to:
Use Enum:enum-type:enum-value naming convention to localize the enum members.
e.g. "Enum:BookType:1": "Adventure"
However, this does not work when using the abp-select tag helper. I can see from the source code for abp-select that the expected format is actually:
Enum:enum-type.enum-toString
e.g. "Enum:BookType.Adventure": "Adventure"
So the documentation is inaccurate, but not a problem, as soon as I changed the resource file enums to the correct format abp-select localised the display values as expected.
However, the datatables source code for the Book List in the same tutorial then breaks:
columnDefs: [
{
title: l('Type'),
data: "type",
render: function (data) {
return l('Enum:BookType:' + data);
}
}
This code expects the enum format to be Enum:enum-type:enum-value and as data is passed back as an int and not the string representation of the enum, the datatable doesn't show the localised data.
As a work around, I am diverging from the tutorial instructions and binding the datatable to a BookDto where BookType is mapped to a string, not an enum. Feels a bit cludgy though.
Am I missing something here ABP?
Great product but this tutorial needs updating either way.

I ran into the same issue but solved it by updating the localization file en.json to match the enum value stored in the database and then changing the book.component.html file to match the abpLocalization property.
When I followed the official documentation at abp, I got this result:
First run with fallback string in HTML component
Acme.BookStore.Application.Shared/Localization/en.json
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store",
"Menu:Books": "Books",
"Actions": "Actions",
"Close": "Close",
"Delete": "Delete",
"Edit": "Edit",
"PublishDate": "Publish date",
"NewBook": "New book",
"Name": "Name",
"Type": "Type",
"Price": "Price",
"CreationTime": "Creation time",
"AreYouSure": "Are you sure?",
"AreYouSureToDelete": "Are you sure you want to delete this item?",
"Enum:BookType.0": "Undefined",
"Enum:BookType.1": "Adventure",
"Enum:BookType.2": "Biography",
"Enum:BookType.3": "Dystopia",
"Enum:BookType.4": "Fantastic",
"Enum:BookType.5": "Horror",
"Enum:BookType.6": "Science",
"Enum:BookType.7": "Science fiction",
"Enum:BookType.8": "Poetry"
}
}
book.component.html in the angular project
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ '::Menu:Books' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6"></div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:BookType.' + row.type | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.publishDate | date }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.price | currency }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
As you can see I have replaced the ":" with a "." as in the localization file.
After change to source-code I get this result:
Enums now translated correctly
I hope this helps you and others struggling with the same issue :)

I just had the same issue. The problem is a mismatch between the declaration of the localization file wrt the usage in the JS code.
In the localization file you can find keys like:
"Enum:BookType.Adventure": "Adventure"
while in the JavaScript it is used:
render: function (data) {
return l('Enum:BookType:' + data);
}
Thus either you change the localization keys as e.g. "Enum:BookType:Adventure": "Adventure" (with ':') or you change the code with this function:
render: function (data) {
return l('Enum:BookType.' + data);
}
where the '.' is concatenated instead of ':'

Related

How to escape right parenthesis in variable?

How can I escape a round bracket (right parenthesis) without closing it in a fragment?
"fragments/questionaire :: questionaire('00001_c-1',
${
{
'...',
'...',
'First 1) ...'
}
},
${
{
'...',
'...',
'...'
}
},'[0,2]')"
Kind of same effect is if keyword new is somewhere in the string.
already tried: 'First 1\) ...' &rpar; ) inside utext
I use it to iterate over an object with questions and hints like:
th:fragment="questionaire(key, questions, hints, rightIndex)"
It's inside a form
<div th:each="aquestion, iterStat : ${questions}" th:with="qid=${key}+'_q-'+${iterStat.index},name='rb-'+${key}">
<div>
<input type="checkbox" th:name="${name}+${'_q-'+iterStat.index}" th:value="0" th:data-s="${iterStat.index}" th:id="${qid}" autocomplete="off" th:checked="${bucket.read('questionaire.'+name+'_q-'+iterStat.index)}==('' + 1)"/>
<label th:for="${qid}" th:text="${aquestion}"></label>
<input type="hidden" th:name="${name}+${'_q-'+iterStat.index}" value="0">
</div>
<div class="hint" th:id="${qid+'--hint'}" th:text="${hints[iterStat.index]}"></div>
</div>
<p class="submitContainer">
<button th:data-qvalidate="|quest${key}|" th:text="#{q.check}">Check</button>
</p>
Following on from my most recent comment in the question...
The least-worst solution I have is to create a Java string variable and add that to your model:
model.put("cp", ")");
where cp means "close parenthesis".
Then you can create a fragment parameter like this:
|foo 1${cp} bar|
And that passes the string foo 1) bar to the fragment without that "selector syntax" error you are currently getting.
<div th:replace="fragments/frag.html :: frag(|foo 1${cp} bar|)"></div>
And my fragment is just this:
<div th:fragment="frag(key)">
<div th:text="${key}"></div>
</div>
I would be happy to learn of a better solution.

Access custom field in POS Receipt

I am using odoo 15 ; I am trying to customize receipt in point_of_sale module
I have a problem regard access the custom filed in company module as following :
My customized module : custom/models/res_company.py
class rescompany(models.Model):
_name = "res.company"
_inherit = "res.company"
#customized fields
x_industry = fields.Char(string='Compnay Industry', translate=True)
my customized view in xml : custom/static/src/xml/custom_pos.xml
<xpath expr="//t[#t-if='receipt.company.logo']" position="before">
<div>
<span style="font-size: smaller;float: left">
<t t-esc="receipt.company.name" />
</span>
</div>
<div>
<div>
<span style="font-size: smaller;float: left">
<t t-esc="receipt.company.x_industry"/>
</span>
</div>
</div>
</xpath>
</t>
</templates>
manifest.py
...
'assets': {
'web.assets_backend': [
"custom/static/src/js/OrderReceipt.js",
],
'web.assets_qweb': [
'custom/static/src/xml/custom_pos.xml',
],
},
...
Now, I don't know how to access x_industry in OrderReceipt.js ?
I tried to follow this link :
Odoo PoS not showing custom fields in receipts
but it is in odoo 13 and I did not understand the parameters I should add to be modified correctly ;
You cannot access a field in PoS even though it has been added through python code. You need to load the specific field in the javascript files for Point of Sale.
Regarding your question, you need to add a field which is specific for a company. The easiest method is to also add the same field in pos.config model and give a related connection with the new field which you added in res.company.
x_industry = fields.Char(string='Compnay Industry', translate=True, related='company_id.x_industry')
Any field added in the pos.config can be accessed from the PoS and PoS receipt.
<t t-esc="env.pos.config.x_industry"/>

Cannot find control with path: angular2

I'm working on a model driven form and I can't get it to add items to a list being displayed with ngFor. I'm currently getting an error when trying to iterate the list.I tried all solutions available.
Error
Cannot find control with path: 'categories -> 0'
ts file
private categories : any= [{name: 'Strict',selected : false},
{name: 'Moderate',selected : true},
{name: 'Flexible',selected : true}];
let allCategories: FormArray = new FormArray([]);
for (let i = 0; i < this.categories.length; i++) {
let fg = new FormGroup({});
fg.addControl(this.categories[i].name, new FormControl(this.categories[i].selected))
allCategories.push(fg)
}
form initialization
categories: allCategories,
Html part
<div formArrayName="categories">
<div *ngFor="let category of categories; let i=index">
<span formGroupName="{{i}}">
<label>
<input type="checkbox" formControlName="{{category.name}}"/>
{{category.name}}
</label>
</span>
</div>
</div>
#Jadoon, I suppose, #DineshArun meant that he wants to list all categories using reactive approach and uses for that FormArray with FormGroups for each category.
The problem is that Angular usually assigns array index as group name by default 0, 1...
But in #DineshArun's case that doesn't work. And in mine case it didn't too, but I've found the solution.
First of all, look at this question and it's marked answer. Rewrite the filling in of your formArray that way, and then assign to formControlName the raw name of the control, which you pointed in your patch() method.

Better practice for js i18n with angular

I wonder to know if there is any bad smell on my practice for i18n on Angular.
I put the I18n translating function on Angular controller (because I don't know how to put it on HTML template file)
And about the i18n scope, I use this way I18n.t("city." + city_name) to indicate that the city_name is under "city" scope. Could I write it in this way I18n.t(city_name, scope: "city") to make it more understandable.
I appreciate every comment and suggestion to enhance my current solution.
Data structure
departures_lst is a list of countries' English name e.g.,: [US, China, Japan]
Each country has many cities name. e.g. [New York, LA, Boston]
Angular controller
App.controller("departures_ctrl", function($scope, $location, $http) {
$http.get("/departures.json")
.success(function (response) {
$scope.departures_lst = response;
});
$scope.get_destinations = function(city_name) {
return $location.url("/depart_from/" + city_name);
};
$scope.i18nCountryName = function(country_name) {
return I18n.t("country." + country_name) + country_name
};
$scope.i18nCityName = function(city_name) {
return I18n.t("city." + city_name) + city_name
};
});
HTML teamplate?
<div class="panel panel-transparent" ng-repeat="departure in departures_lst">
<h5>{{i18nCountryName(departure.country)}}</h5>
<li class="col-sm-3 col-lg-3 col-xs-3" ng-repeat="city in departure.cities">
<a ng-click="get_destinations(city)">
<i class="fa fa-plane"></i>
{{i18nCityName(city)}}
</a>
</li>
</div>
You should always try to put localization in the markup (as much as possible), that way you further encapsulate layout from your logic and data. I have always used the great angular-localization plug in. You get some great filters and directives to play with that have parametrization and other features built in. For example:
You have a string where you have to insert the name of a user, you define the string in your localized file as:
"some-loc-id-tag": "insert the user name {user} here!"
And in your controller scope have the property:
$scope.model.userName
And can display the name of the user with the localized string like so in HTML:
<div data-i18n="loc.some-loc-id-tag" data-user="{{model.userName}}"></div>
Check it out:
https://github.com/doshprompt/angular-localization

Rails - Add HTML attribute without setting a value

I'm trying to create an image_tag and specify a data- attribute that does not have any value set to it. I'm trying to add data-tooltip, for use with Foundation 5 tooltips. It seems that if any value is actually set to this, Foundation uses the same tooltip text every time and ignores the title attribute of that element (so every tooltip will say whatever the first one you hovered on was... which seems buggy in and of itself on Foundation's part also)
This is what I need to generate:
<img src="[whatever]" title="My Tooltip" data-tooltip />
This will not work for me:
<img src="[whatever]" title="My Tooltip" data-tooltip="[insert anything here]" />
I have tried a number of different combinations, and read documentation, but it seems no matter what I put as the value, it ends up generating it like data-tooltip="null", or true, or false, or any string I pass.
image_tag(my_image, class: 'has-tip', title: "My Title Here", data: { tooltip: true })
Try to pass in empty string as follows:
image_tag(my_image, class: 'has-tip', title: "My Title Here", data: { tooltip: "" })
In Rails 4.1.4 using above tip :"data-tooltip" => '' renders data-tooltip without value.
For an attribute with no value like multiple <input multiple type="file">, you can override the attribute default name, by uppercasing and setting an empty string. For example input_html: { Multiple: '' } But this is a hack.
In rails 5, I was trying to add itemscope attribute with no value in the following link tag scenario:
<%= link_to example_path(#example) do %>
<span>
<%= #example.name %>
</span>
<% end %>
I needed the resulting html a tag to show the itemscope attribute without any value like so:
<a itemscope href="example/path">
<span>
some text
</span>
</a>
Notice the itemscope has no ="" or itemscope="itemscope".
I tried solutions from SO and other places and the only thing that worked for me was adding the following to the link_to tag: " itemscope" => ''. Notice the space between the first double quote and the word itemscope.
This seems to generate the desired outcome and also validated as schema.org tag on google (that is what i used the tag for).

Resources