Today, I am going to show you how to create a Liferay portlet with localized input value. You also know how to put a portlet in Control Panel and embed a portlet in theme.
When doing with localization, you can have a couple of choices. If you are in theme template files, you can use #language("your_language_key"), and if you are in portlet view file (.jsp file...), it is LanguageUtil.get(pageContext, "your_language_key"). You will have localization ability.
But it is all the things you know already. You prepare your language properties files, put words on it, along with the same key, and then you show the correct language sentence when user change their language in Portal. What about the value that user puts? Do you want to localize it? Sure. You can see what it looks like by creating a structure or a template in Web Content in Control Panel.
Now, for example, we have to create a manual Menu portlet that allows admin user create the menu on his own. We will localize the Menu label.
We have two portlets, one for managing Menu item in Control Panel, and the another for displaying Menu bar in your theme. These are working on the same Menu Item data model.
Firstly, create Menu Item entity in service.xml file, like below:
<entity name="MenuItem" local-service="true" remote-service="true" cache-enabled="false">In this case, pay your attention on:
<!-- PK fields -->
<column name="menuItemId" type="long" primary="true" />
<!-- Audit fields -->
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" primary="false"/>
<column name="modifiedDate" type="Date" primary="false"/>
<!-- Other fields -->
<column name="name" type="String" localized="true"/>
<column name="description" type="String" localized="true" />
<column name="path" type="String" />
<column name="targetType" type="String" />
<column name="parentId" type="long" />
<column name="weight" type="int"></column>
<order by="asc">
<order-column name="menuItemId" order-by="asc"/>
</order>
<!-- Finder methods -->
<finder name="Name" return-type="Collection">
<finder-column name="name" />
</finder>
<finder name="ParentId" return-type="Collection">
<finder-column name="parentId" />
</finder>
</entity>
<column name="name" type="String" localized="true"/>
<column name="description" type="String" localized="true" />It makes the Portal save the user input value in xml format that supports localization. One thing else you should know is I set cache-enabled="false". I don't know how cache in portlet level works but if you set this to true, when user adds new value to database, it does not affect to view immediately until I redeploy source code again.
Look at portlet-model-hints.xml file,
<model-hints>From there, in view files, you can use aui taglib to display form input that supports localization. This is my code on edit.jsp file:
<model name="vn.edu.bvu.model.MenuItem">
<field name="menuItemId" type="long" />
<field name="companyId" type="long" />
<field name="userId" type="long" />
<field name="userName" type="String" />
<field name="createDate" type="Date" />
<field name="modifiedDate" type="Date" />
<field name="name" type="String" localized="true" />
<field name="description" type="String" localized="true" />
<field name="path" type="String" />
<field name="targetType" type="String" />
<field name="parentId" type="long" />
<field name="weight" type="int" />
</model>
</model-hints>
<%@ include file="/html/menu/init.jsp"%>The magic thing comes from portlet-model-hints.xml file to <aui:input ...> taglib. AUI taglib automatically recognize localized=true and add more component to allow user add more language translation.
<portlet:actionURL var="addMenuItemURL" name="add"></portlet:actionURL>
<%
long menuItemId = ParamUtil.getLong(renderRequest, "menuItemId");
MenuItem mi = null;
if (menuItemId > 0) {
mi = MenuItemLocalServiceUtil.getMenuItem(menuItemId);
}
List<MenuItem> list = MenuItemLocalServiceUtil.getMenuItems(0, MenuItemLocalServiceUtil.getMenuItemsCount());
%>
<aui:form action="<%= addMenuItemURL %>" method="post">
<aui:fieldset>
<aui:model-context model="<%= MenuItem.class %>" bean="<%= mi %>" />
<aui:input name="menuItemId" type="hidden" />
<aui:input name="name" label="menu-item-name"/>
<aui:input name="description" label="menu-item-description"/>
<aui:input name="path" label="menu-item-path"/>
<aui:select name="targetType" label="menu-item-target-type">
<aui:option selected="<%= mi != null ? (mi.getTargetType().equals(\"_self\") ? true : false) : false %>" value="_self">_self</aui:option>
<aui:option selected="<%= mi != null ? (mi.getTargetType().equals(\"_blank\") ? true : false) : false %>" value="_blank">_blank</aui:option>
<aui:option selected="<%= mi != null ? (mi.getTargetType().equals(\"_parent\") ? true : false) : false %>" value="_parent">_parent</aui:option>
<aui:option selected="<%= mi != null ? (mi.getTargetType().equals(\"_top\") ? true : false) : false %>" value="_top">_top</aui:option>
</aui:select>
<aui:input name="weight" label="menu-item-weight"/>
<aui:select name="parentId" label="menu-item-parentId">
<aui:option selected="<%= mi != null ? (mi.getParentId() == 0 ? true : false) : false %>" value="<%= 0 %>"><%= StringPool.BLANK %></aui:option>
<%
for(int i = 0; i < list.size(); i++) {
MenuItem item = list.get(i);
if(item.getMenuItemId() != menuItemId) {
%>
<aui:option selected="<%= item.getMenuItemId() == menuItemId %>" value="<%= item.getMenuItemId() %>"><%= item.getName(currentLocale) %></aui:option>
<%
}
}
%>
</aui:select>
<aui:button name="submit" type="submit" value="Add"/>
</aui:fieldset>
</aui:form>
See more benefits from model-hints from this link https://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/using-model-hints-liferay-portal-6-1-dev-guide-en.
In view result file, see my code below:
<%@ include file="/html/menu/init.jsp"%>MenuItem model has function help us to fetch Menu label corresponding to current locale.
<portlet:renderURL var="addMenuItemUrl" portletMode="edit" />
<liferay-ui:search-container delta="5" emptyResultsMessage="no-menu-items-were-found">
<liferay-ui:search-container-results>
<%
List<MenuItem> list = MenuItemLocalServiceUtil
.getMenuItems(0, MenuItemLocalServiceUtil
.getMenuItemsCount());
List<MenuItem> tempResults = ListUtil.subList(list,searchContainer.getStart(), searchContainer.getEnd());
int tempTotal = list.size();
pageContext.setAttribute("results", tempResults);
pageContext.setAttribute("total", tempTotal);
%>
</liferay-ui:search-container-results>
<liferay-ui:search-container-row className="vn.edu.bvu.model.MenuItem"
keyProperty="menuItemId" modelVar="item">
<liferay-ui:search-container-column-text name="menu-item-id"
value="<%=StringUtil.valueOf(item.getMenuItemId()) %>" />
<liferay-ui:search-container-column-text name="menu-item-name"
value="<%=item.getName(currentLocale) %>" />
<liferay-ui:search-container-column-text name="menu-item-description"
value="<%=item.getDescription(currentLocale)%>" />
<liferay-ui:search-container-column-text name="menu-item-path"
value="<%=item.getPath()%>" />
<liferay-ui:search-container-column-text name="menu-item-target-type"
value="<%=item.getTargetType()%>" />
<liferay-ui:search-container-column-text name="menu-item-weight"
value="<%=String.valueOf(item.getWeight())%>" />
<liferay-ui:search-container-column-text name="menu-item-parentId"
value="<%= item.getParentId() == 0 ? StringPool.BLANK : MenuItemLocalServiceUtil.getMenuItem(item.getParentId()).getName(currentLocale) %>" />
<liferay-ui:search-container-column-jsp path="/html/menu/buttons.jsp"
align="right" />
</liferay-ui:search-container-row>
<liferay-ui:search-iterator />
</liferay-ui:search-container>
<a href="<%=addMenuItemUrl%>">Add new</a>
/htm/menu/buttons.jsp file:
<%@ include file="/html/menu/init.jsp" %>
<%
ResultRow rslt = (ResultRow)renderRequest.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);
MenuItem mi = (MenuItem)rslt.getObject();
%>
<liferay-ui:icon-menu>
<portlet:actionURL name="edit" var="editUrl">
<portlet:param name="menuItemId" value="<%= StringUtil.valueOf(mi.getMenuItemId()) %>"/>
</portlet:actionURL>
<portlet:actionURL name="delete" var="deleteUrl">
<portlet:param name="menuItemId" value="<%=StringUtil.valueOf(mi.getMenuItemId()) %>"/>
</portlet:actionURL>
<liferay-ui:icon image="edit" message="Edit" url="<%= editUrl %>"/>
<liferay-ui:icon image="delete" message="Delete" url="<%= deleteUrl %>"/>
</liferay-ui:icon-menu>
But wait a minute, how can we save data with localization? Here it is:
public void add(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException, SystemException, PortalException {
Map<Locale, String> name = LocalizationUtil.getLocalizationMap(actionRequest, "name");See my highlighted code. We save a map with locale value, not just a single value as usual.
Map<Locale, String> description = LocalizationUtil.getLocalizationMap(actionRequest, "description");
String path = ParamUtil.getString(actionRequest, "path");
String targetType = ParamUtil.getString(actionRequest, "targetType");
int weight = ParamUtil.getInteger(actionRequest, "weight");
long parentId = ParamUtil.getLong(actionRequest, "parentId");
long menuItemId = ParamUtil.getLong(actionRequest, "menuItemId");
MenuItem menuItem = null;
if(menuItemId > 0) {
menuItem = MenuItemLocalServiceUtil.getMenuItem(menuItemId);
} else {
menuItemId = CounterLocalServiceUtil.increment(MenuPortlet.class.getName());
menuItem = MenuItemLocalServiceUtil.createMenuItem(menuItemId);
}
menuItem.setNameMap(name);
menuItem.setDescriptionMap(description);
menuItem.setPath(path);
menuItem.setTargetType(targetType);
menuItem.setWeight(weight);
menuItem.setParentId(parentId);
MenuItemLocalServiceUtil.updateMenuItem(menuItem);
actionResponse.setPortletMode(PortletMode.VIEW);
}
Add Menu portlet to Control Panel:
Add 2 control panel entry element to portlet definition in liferay-portlet.xml, like below:
<portlet>Also, in liferay-display.xml, add this portlet to hidden categrory to hide it from user selection in add Portlet list on their pages:
<portlet-name>menu</portlet-name>
<icon>/icon.png</icon>
<control-panel-entry-category>
content
</control-panel-entry-category>
<control-panel-entry-weight>1.5</control-panel-entry-weight>
<instanceable>false</instanceable>
<header-portlet-css>/css/menu/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/menu/main.js
</footer-portlet-javascript>
<css-class-wrapper>menu-portlet</css-class-wrapper>
</portlet>
<category name="category.hidden">Embed Display Menu portlet to theme:
<portlet id="menu"></portlet>
</category>
After you get all menu items you need to display in menu bar, embed Menu Display portlet to theme to make it visible to all pages and does not let user change, move or re-configure it. In navigation.vm file, do something like this:
<nav class="$nav_css_class menu" id="navigation">That's all. Tell me if you have any problem. All comments are welcome. See you next time.
#set ($VOID = $velocityPortletPreference.setValue('display-style', '1'))
#set ($VOID = $velocityPortletPreference.setValue('portlet-setup-show-borders', 'false'))
#set ($portletId = "menudisplay_WAR_portalportlet")
$theme.runtime($portletId, '', $velocityPortletPreferences.toString())
#set ($VOID = $velocityPortletPreferences.reset())
</nav>
No comments:
Post a Comment