From 524e544516e2373908cfb3d56f359a7f1511e83e Mon Sep 17 00:00:00 2001
From: Xiaowu Zhang <xiaowu.zhang@tiolive.com>
Date: Wed, 16 Nov 2016 12:54:09 +0000
Subject: [PATCH] erp5_web_renderjs_ui: available to translate

---
 .../ERP5Document_getHateoas.py                |   66 +-
 .../test.erp5.testHalJsonStyle.py             |  122 +-
 .../Web%20Site/create_translation_data.xml    |   85 +
 .../rjs_gadget_erp5_appcache.xml              |    1 -
 .../rjs_gadget_erp5_global_js.js              |    2 +-
 .../rjs_gadget_erp5_global_js.xml             |    4 +-
 .../rjs_gadget_erp5_header_html.html          |   23 +
 .../rjs_gadget_erp5_header_html.xml           |    4 +-
 .../rjs_gadget_erp5_launcher_html.html        |    3 +
 .../rjs_gadget_erp5_launcher_html.xml         |    4 +-
 .../rjs_gadget_erp5_listbox_html.html         |    4 +
 .../rjs_gadget_erp5_listbox_html.xml          |    4 +-
 .../rjs_gadget_erp5_listbox_js.js             |   33 +-
 .../rjs_gadget_erp5_listbox_js.xml            |    4 +-
 ...gadget_erp5_multirelationstringfield_js.js |    4 +-
 ...adget_erp5_multirelationstringfield_js.xml |    4 +-
 .../rjs_gadget_erp5_page_history_js.js        |    4 +-
 .../rjs_gadget_erp5_page_history_js.xml       |    4 +-
 ...rjs_gadget_erp5_page_relation_search_js.js |    7 +
 ...js_gadget_erp5_page_relation_search_js.xml |    4 +-
 .../rjs_gadget_erp5_page_search_html.html     |    6 +
 .../rjs_gadget_erp5_page_search_html.xml      |    4 +-
 .../rjs_gadget_erp5_page_worklist_html.html   |    3 +
 .../rjs_gadget_erp5_page_worklist_html.xml    |    4 +-
 .../rjs_gadget_erp5_page_worklist_js.js       |    2 +-
 .../rjs_gadget_erp5_page_worklist_js.xml      |    4 +-
 .../rjs_gadget_erp5_panel_html.html           |    2 +-
 .../rjs_gadget_erp5_panel_html.xml            |    4 +-
 .../rjs_gadget_erp5_panel_js.js               |    2 +-
 .../rjs_gadget_erp5_panel_js.xml              |    4 +-
 .../rjs_gadget_erp5_pt_actionpage_html.html   |    4 +
 .../rjs_gadget_erp5_pt_actionpage_html.xml    |    4 +-
 .../rjs_gadget_erp5_pt_frontpage_html.html    |    3 +
 .../rjs_gadget_erp5_pt_frontpage_html.xml     |    4 +-
 .../rjs_gadget_erp5_pt_frontpage_js.js        |    3 +-
 .../rjs_gadget_erp5_pt_frontpage_js.xml       |    4 +-
 ...js_gadget_erp5_pt_preferencepage_html.html |   17 +-
 ...rjs_gadget_erp5_pt_preferencepage_html.xml |    4 +-
 .../rjs_gadget_erp5_pt_preferencepage_js.js   |  108 +-
 .../rjs_gadget_erp5_pt_preferencepage_js.xml  |    4 +-
 .../rjs_gadget_erp5_pt_tabpage_html.html      |    4 +
 .../rjs_gadget_erp5_pt_tabpage_html.xml       |    4 +-
 .../rjs_gadget_erp5_relation_input_html.html  |    8 +-
 .../rjs_gadget_erp5_relation_input_html.xml   |    4 +-
 .../rjs_gadget_erp5_relation_input_js.js      |   19 +-
 .../rjs_gadget_erp5_relation_input_js.xml     |    4 +-
 .../rjs_gadget_erp5_relationstringfield_js.js |    1 +
 ...rjs_gadget_erp5_relationstringfield_js.xml |    4 +-
 .../rjs_gadget_erp5_router_js.js              |   45 +-
 .../rjs_gadget_erp5_router_js.xml             |    4 +-
 .../rjs_gadget_erp5_searcheditor_html.html    |   15 +-
 .../rjs_gadget_erp5_searcheditor_html.xml     |    4 +-
 .../rjs_gadget_translation_html.html          |    1 -
 .../rjs_gadget_translation_html.xml           |    8 +-
 .../rjs_gadget_translation_js.js              |  208 +-
 .../rjs_gadget_translation_js.xml             |    4 +-
 .../web_page_module/rjs_plugin_i18next_js.js  | 2889 -----------------
 .../web_page_module/rjs_plugin_i18next_js.xml |  320 --
 .../web_site_module/renderjs_runner.xml       |    2 +-
 .../Base_createTranslateData.py               |   54 +
 .../Base_createTranslateData.xml              |   62 +
 .../Base_getListFileFromAppcache.py           |   21 +
 .../Base_getListFileFromAppcache.xml          |   62 +
 .../WebSite_createTranslationData.xml         |  131 +
 .../your_translation_data_file.xml            |  277 ++
 .../WebSection_renderDefaultPageAsGadget.py   |   24 +-
 .../erp5_web_renderjs_ui/WebSite_login.py     |    3 +-
 .../WebSite_viewRecoverAccount.zpt            |    6 +-
 .../erp5_web_renderjs_ui/login_form.zpt       |   10 +-
 .../bt/template_action_path_list              |    1 +
 70 files changed, 1331 insertions(+), 3444 deletions(-)
 create mode 100644 bt5/erp5_web_renderjs_ui/ActionTemplateItem/portal_types/Web%20Site/create_translation_data.xml
 delete mode 100644 bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.js
 delete mode 100644 bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.xml
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.py
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.xml
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.py
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.xml
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData.xml
 create mode 100644 bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData/your_translation_data_file.xml

diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
index 0ac07b2303..cfcd2996f5 100644
--- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
+++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
@@ -6,6 +6,7 @@ from ZODB.POSException import ConflictError
 import datetime
 import time
 from email.Utils import formatdate
+import re
 
 if REQUEST is None:
   REQUEST = context.REQUEST
@@ -71,6 +72,7 @@ url_template_dict = {
 }
 
 default_document_uri_template = url_template_dict["jio_get_template"]
+Base_translateString = context.getPortalObject().Base_translateString
 
 def getRealRelativeUrl(document):
   return '/'.join(portal.portal_url.getRelativeContentPath(document))
@@ -107,7 +109,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
       # XXX Message can not be converted to json as is
       "items": field.get_value("items"),
@@ -122,7 +124,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
       "items": field.get_value("items"),
       "select_first_item": field.get_value("first_item"),
@@ -137,7 +139,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
       # XXX Message can not be converted to json as is
       "items": field.get_value("items")
@@ -155,7 +157,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
     }
     result["default"] = getFieldDefault(traversed_document, field, result["key"], value)
@@ -182,7 +184,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
       "date_only": field.get_value("date_only"),
       "ampm_time_style": field.get_value("ampm_time_style"),
@@ -208,7 +210,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
     jump_reference_list = []
     if portal_type_list:
       portal_type_list = [x[0] for x in portal_type_list]
-
+      translated_portal_type = [Base_translateString(x) for x in portal_type_list]
       # ported from Base_jumpToRelatedDocument\n
       base_category = field.get_value('base_category')
       kw = {}
@@ -226,7 +228,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
         {"portal_type": portal_type_list}
       ).asSearchTextExpression(sql_catalog)})
     }
-    title = field.get_value("title"),
+    title = field.get_value("title")
     column_list = field.get_value("columns")
     proxy_listbox_ids = field.get_value("proxy_listbox_ids")
 
@@ -254,16 +256,19 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
           }
           result.pop("list_method_template", None)
           result["list_method"] = "portal_catalog"
-          result["title"] = title
+          result["title"] = Base_translateString(title)
           #set default listbox's column list to relation's column list
           if tmp[0] == 'Base_viewRelatedObjectListBase' and len(column_list) > 0:
-            result["column_list"] = column_list
-          listbox[grain[1]] = result
+            result["column_list"] = []
+            for tmp_column in column_list:
+              result["column_list"].append((tmp_column[0], Base_translateString(tmp_column[1])))
+          listbox[Base_translateString(grain[1])] = result
           break
 
 
     result = {
       "url": relative_url,
+      "translated_portal_types": translated_portal_type,
       "portal_types": portal_type_list,
       "query": query,
       "catalog_index": field.get_value('catalog_index'),
@@ -275,7 +280,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": title,
+      "title": Base_translateString(title),
       "required": field.get_value("required"),
       "proxy_listbox_ids_len": len(proxy_listbox_ids),
       "listbox": listbox
@@ -305,7 +310,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title")
+      "title": Base_translateString(field.get_value("title")),
     }
     result["default"] = getFieldDefault(traversed_document, field, result["key"], value)
   elif meta_type == "MultiCheckBoxField":
@@ -316,7 +321,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "required": field.get_value("required"),
       # XXX Message can not be converted to json as is
       "items": field.get_value("items"),
@@ -330,18 +335,29 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "css_class": field.get_value("css_class"),
       "hidden": field.get_value("hidden"),
       "description": field.get_value("description"),
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "url": field.get_value("gadget_url"),
       "sandbox": field.get_value("js_sandbox"),
     }
     result["default"] = getFieldDefault(traversed_document, field, result["key"], value)
   elif meta_type == "ListBox":
     # XXX Not implemented
-    column_list = field.get_value("columns")
-    editable_column_list = field.get_value('editable_columns')
+    column_list = []
+    for tmp in field.get_value("columns"):
+      column_list.append((tmp[0], Base_translateString(tmp[1])))
+    editable_column_list = []
+    for tmp in field.get_value('editable_columns'):
+      editable_column_list.append((tmp[0], Base_translateString(tmp[1])))
+
+    sort_column_list_tmp = []
+
+    for tmp in field.get_value('sort_columns'):
+      sort_column_list_tmp.append((tmp[0], Base_translateString(tmp[1])))
+
+    search_column_list_tmp = []
+    for tmp in field.get_value('search_columns'):
+      search_column_list_tmp.append((tmp[0], Base_translateString(tmp[1])))
 
-    sort_column_list_tmp = field.get_value('sort_columns')
-    search_column_list_tmp = field.get_value('search_columns')
     sort_column_list = []
     search_column_list = []
     
@@ -435,7 +451,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
       "editable_column_list": editable_column_list,
       "show_anchor": field.get_value("anchor"),
 #       "line_list": line_list,
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "key": key,
       "portal_type": portal_types,
       "lines": lines,
@@ -455,7 +471,7 @@ def renderField(traversed_document, field, form_relative_url, value=None, meta_t
     result = {
       "type": meta_type,
       "_debug": "Unsupported field type",
-      "title": field.get_value("title"),
+      "title": Base_translateString(field.get_value("title")),
       "key": key,
     }
   return result
@@ -627,7 +643,7 @@ def renderFormDefinition(form, response_dict):
 
       group_list.append((group['gid'], field_list))
   response_dict["group_list"] = group_list
-  response_dict["title"] = form.getTitle()
+  response_dict["title"] = Base_translateString(form.getTitle())
   response_dict["pt"] = form.pt
   response_dict["action"] = form.action
 
@@ -743,7 +759,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
                             .getRelativeUrl(), 
           "script_id": script.id
         },
-        "name": traversed_document.getPortalType(),
+        "name": Base_translateString(traversed_document.getPortalType())
       }
       
     # Return info about container
@@ -757,7 +773,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
             "relative_url": container.getRelativeUrl(), 
             "script_id": script.id
           },
-          "name": container.getTitle(),
+          "name": Base_translateString(container.getTitle()),
         }
   
     # XXX Loop on form rendering
@@ -773,7 +789,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
         erp5_action_list.append({
           'href': '%s' % view_action['url'],
           'name': view_action['id'],
-          'title': view_action['title']
+          'title': Base_translateString(view_action['title'])
         })
         # Try to embed the form in the result
         if (view == view_action['id']):
@@ -1214,7 +1230,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
             'href': url_template_dict["jio_search_template"] % {
                       "query": make_query({"query": query})
                     },
-            'name': action['name'],
+            'name': Base_translateString(re.sub(r' \(\d+\)$', '', action['name'])),
             'count': action['count'],
             'module': default_document_uri_template % {
                         "relative_url": worklist_module_id
diff --git a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py
index f8e0272cc3..fc4057706e 100644
--- a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py
+++ b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py
@@ -1076,12 +1076,130 @@ class TestERP5Document_getHateoas_mode_worklist(ERP5HALJSONStyleSkinsMixin):
     result_dict = json.loads(result)
     self.assertEqual(result_dict['_links']['self'], {"href": "http://example.org/bar"})
 
-    work_list = [x for x in result_dict['worklist'] if x['name'].startswith('Draft To Validate (')]
+    work_list = [x for x in result_dict['worklist'] if x['name'].startswith('Draft To Validate')]
     self.assertEqual(len(work_list), 1)
     self.assertTrue(work_list[0]['count'] > 0)
-    self.assertEqual(work_list[0]['name'], 'Draft To Validate (%i)' % work_list[0]['count'])
+    self.assertEqual(work_list[0]['name'], 'Draft To Validate')
     self.assertEqual(work_list[0]['module'], 'urn:jio:get:bar_module')
     self.assertEqual(work_list[0]['href'], 'urn:jio:allDocs?query=portal_type%3A%28%22Bar%22%20OR%20%22Foo%22%29%20AND%20simulation_state%3A%22draft%22')
 
     self.assertEqual(result_dict['_debug'], "worklist")
 
+class TestERP5Document_getHateoas_translation(ERP5HALJSONStyleSkinsMixin):
+  code_string = "\
+from Products.CMFCore.utils import getToolByName\n\
+translation_service = getToolByName(context, 'Localizer', None)\n\
+if translation_service is not None :\n\
+  try:\n\
+    if not encoding:\n\
+      return translation_service.translate(catalog, msg, lang=lang, **kw)\n\
+    msg = translation_service.translate(catalog, msg, lang=lang, **kw)\n\
+    if same_type(msg, u''):\n\
+      msg = msg.encode(encoding)\n\
+    return msg\n\
+  except AttributeError:\n\
+    pass\n\
+return msg"
+
+  @simulate('Base_getRequestUrl', '*args, **kwargs',
+      'return "http://example.org/bar"')
+  @simulate('Base_getRequestHeader', '*args, **kwargs',
+            'return "application/hal+json"')
+  @simulate('Base_translateString', 'msg, catalog="ui", encoding="utf8", lang="wo", **kw',
+  code_string)
+
+  @changeSkin('Hal')
+  def test_getHateoasBulk_default_view_translation(self):
+    self.portal.Base_createUITestLanguages()
+    param_dict = [
+      { 'message': 'Title', 'translation': 'biaoti', 'language': 'wo'},
+      { 'message': 'Draft To Validate', 'translation': 'daiyanzhen', 'language': 'wo'},
+      { 'message': 'Foo', 'translation': 'Foo_zhongwen', 'language': 'wo'}]
+    for tmp in param_dict:
+      self.portal.Base_addUITestTranslation(message = tmp['message'], translation = tmp['translation'], language = tmp['language'])
+    document = self._makeDocument()
+    fake_request = do_fake_request("POST")
+
+    result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
+      REQUEST=fake_request,
+      mode="bulk",
+      bulk_list=json.dumps([{"relative_url": document.getRelativeUrl(), "view": "view"}])
+    )
+    self.assertEquals(fake_request.RESPONSE.status, 200)
+    self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
+      "application/hal+json"
+    )
+    result_dict = json.loads(result)
+    self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_title']['title'], 'biaoti')
+    self.assertEqual(result_dict['result_list'][0]['_links']['type']['name'], 'Foo_zhongwen')
+    self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['listbox']['column_list'][1][1], 'biaoti')
+
+  @simulate('Base_getRequestUrl', '*args, **kwargs',
+      'return "http://example.org/bar"')
+  @simulate('Base_getRequestHeader', '*args, **kwargs',
+            'return "application/hal+json"')
+  @simulate('Base_translateString', 'msg, catalog="ui", encoding="utf8", lang="wo", **kw',
+  code_string)
+
+  @changeSkin('Hal')
+  def test_getHateoasDocument_result_translation(self):
+    document = self._makeDocument()
+    fake_request = do_fake_request("GET")
+    result = document.ERP5Document_getHateoas(REQUEST=fake_request)
+    self.assertEquals(fake_request.RESPONSE.status, 200)
+    self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
+      "application/hal+json"
+    )
+    result_dict = json.loads(result)
+
+    self.assertEqual(result_dict['_links']['type']['href'], 'urn:jio:get:portal_types/%s' % document.getPortalType())
+    self.assertEqual(result_dict['_links']['type']['name'], 'Foo_zhongwen')
+
+    self.assertEqual(result_dict['title'].encode("UTF-8"), document.getTitle())
+    self.assertEqual(result_dict['_debug'], "root")
+
+  @simulate('Base_getRequestUrl', '*args, **kwargs',
+      'return "http://example.org/bar"')
+  @simulate('Base_getRequestHeader', '*args, **kwargs',
+            'return "application/hal+json"')
+  @simulate('Base_translateString', 'msg, catalog="ui", encoding="utf8", lang="wo", **kw',
+  code_string)
+  @changeSkin('Hal')
+  def test_getHateoasWorklist_default_view_translation(self):
+    # self._makeDocument()
+    fake_request = do_fake_request("GET")
+    result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
+      REQUEST=fake_request,
+      mode="worklist"
+    )
+    self.assertEquals(fake_request.RESPONSE.status, 200)
+    self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
+      "application/hal+json"
+    )
+    result_dict = json.loads(result)
+    self.assertEqual(result_dict['_links']['self'], {"href": "http://example.org/bar"})
+    work_list = [x for x in result_dict['worklist'] if x['name'].startswith('daiyanzhen')]
+    self.assertEqual(len(work_list), 1)
+    self.assertEqual(work_list[0]['name'], 'daiyanzhen')
+    self.assertTrue(work_list[0]['count'] > 0)
+    self.assertEqual(work_list[0]['module'], 'urn:jio:get:bar_module')
+    self.assertEqual(work_list[0]['href'], 'urn:jio:allDocs?query=portal_type%3A%28%22Bar%22%20OR%20%22Foo%22%29%20AND%20simulation_state%3A%22draft%22')
+
+    self.assertEqual(result_dict['_debug'], "worklist")
+
+  @simulate('Base_getRequestUrl', '*args, **kwargs',
+      'return "http://example.org/bar"')
+  @simulate('Base_getRequestHeader', '*args, **kwargs',
+            'return "application/hal+json"')
+  @simulate('Base_translateString', 'msg, catalog="ui", encoding="utf8", lang="wo", **kw',
+  code_string)
+  @changeSkin('Hal')
+  def test_getHateoasForm_no_view(self):
+    fake_request = do_fake_request("GET")
+    result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(REQUEST=fake_request, mode="traverse", relative_url="portal_skins/erp5_ui_test/Foo_view")
+    self.assertEquals(fake_request.RESPONSE.status, 200)
+    self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
+      "application/hal+json"
+    )
+    result_dict = json.loads(result)
+    self.assertEqual(result_dict['title'], 'Foo_zhongwen')
diff --git a/bt5/erp5_web_renderjs_ui/ActionTemplateItem/portal_types/Web%20Site/create_translation_data.xml b/bt5/erp5_web_renderjs_ui/ActionTemplateItem/portal_types/Web%20Site/create_translation_data.xml
new file mode 100644
index 0000000000..1e10375aaf
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/ActionTemplateItem/portal_types/Web%20Site/create_translation_data.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>action</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+            </value>
+        </item>
+        <item>
+            <key> <string>categories</string> </key>
+            <value>
+              <tuple>
+                <string>action_type/object_action</string>
+              </tuple>
+            </value>
+        </item>
+        <item>
+            <key> <string>category</string> </key>
+            <value> <string>object_action</string> </value>
+        </item>
+        <item>
+            <key> <string>condition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>icon</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>create_translation_data</string> </value>
+        </item>
+        <item>
+            <key> <string>permissions</string> </key>
+            <value>
+              <tuple>
+                <string>View</string>
+              </tuple>
+            </value>
+        </item>
+        <item>
+            <key> <string>portal_type</string> </key>
+            <value> <string>Action Information</string> </value>
+        </item>
+        <item>
+            <key> <string>priority</string> </key>
+            <value> <float>1.0</float> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>Create Translation Data</string> </value>
+        </item>
+        <item>
+            <key> <string>visible</string> </key>
+            <value> <int>1</int> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="Expression" module="Products.CMFCore.Expression"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>text</string> </key>
+            <value> <string>string:${object_url}/WebSite_createTranslationData</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_appcache.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_appcache.xml
index 94475705ac..1a29d50eeb 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_appcache.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_appcache.xml
@@ -230,7 +230,6 @@ gadget_translation.html\n
 gadget_translation.js\n
 gadget_translation_data.js\n
 handlebars.js\n
-i18next.js\n
 jiodev.js\n
 renderjs.js\n
 rsvp.js\n
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.js
index 96f5e2ad99..49d497af97 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.js
@@ -8,7 +8,7 @@
       .push(function () {
         var title = erp5_document.title,
           portal_type = erp5_document._links.type.name;
-        if (/ Module$/.test(portal_type)) {
+        if (/ Module$/.test(erp5_document._links.type.href)) {
           return portal_type;
         }
         return portal_type + ': ' + title;
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.xml
index 769c71ad84..0de0705b07 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_global_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>950.28789.14822.18670</string> </value>
+                <value> <string>954.14461.31508.53930</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1460380170.56</float>
+                        <float>1476894652.41</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.html
index 19c7898690..295f6a5379 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.html
@@ -1,6 +1,29 @@
 <!DOCTYPE html>
 <html>
   <head>
+    <!--
+      data-i18n=Front
+      data-i18n=Previous
+      data-i18n=Cancel
+      data-i18n=Back
+      data-i18n=Editable
+      data-i18n=Viewable
+      data-i18n=New
+      data-i18n=Save
+      data-i18n=Proceed
+      data-i18n=Add
+      data-i18n=Filter
+      data-i18n=Views
+      data-i18n=Jump
+      data-i18n=Delete
+      data-i18n=Export
+      data-i18n=Actions
+      data-i18n=Cut
+      data-i18n=Add
+      data-i18n=Previous
+      data-i18n=Next
+      data-i18n=Loading
+    -->
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
     <title>ERP5 Header</title>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.xml
index d413c0c826..1e9fff0d7b 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_header_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.10496.5559.9130</string> </value>
+                <value> <string>954.5917.19875.40379</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1479462688.84</float>
+                        <float>1474563958.55</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.html
index ca0109e60d..5329b5322d 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.html
@@ -15,6 +15,9 @@
     <script data-renderjs-configuration="default_view_reference" type="text/x-renderjs-configuration">${default_view_reference}</script>
     <script data-renderjs-configuration="hateoas_url" type="text/x-renderjs-configuration">${hateoas_url}</script>
     <script data-renderjs-configuration="frontpage_gadget" type="text/x-renderjs-configuration">${frontpage_gadget}</script>
+    <script data-renderjs-configuration="language_map" type="text/x-renderjs-configuration">${language_map}</script>
+    <script data-renderjs-configuration="default_selected_language" type="text/x-renderjs-configuration">${default_selected_language}</script>
+    <script data-renderjs-configuration="website_url_set" type="text/x-renderjs-configuration">${website_url_set}</script>
 
     <script src="rsvp.js"></script>
     <script src="renderjs.js"></script>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.xml
index 3eca1b65e0..b090830f9f 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_html.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.19466.27249.10478</string> </value>
+                <value> <string>954.5916.8255.62617</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1479222440.45</float>
+                        <float>1475848425.64</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html
index 9c8356cad4..9e742c6325 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.html
@@ -1,6 +1,10 @@
 <!DOCTYPE html>
 <html>
   <head>
+   <!--
+     data-i18n=No records
+     data-i18n=Records
+   -->
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
     <title>ERP5 Listbox</title>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml
index 0ab97364b2..ef4d09ee9d 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.47421.47694.22459</string> </value>
+                <value> <string>953.48474.52969.47820</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476967547.86</float>
+                        <float>1474554275.61</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js
index 627dfa7ed2..27fb41c7d7 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js
@@ -36,10 +36,11 @@
     error_message_source = gadget_klass.__template_element
                          .getElementById("error-message-template")
                          .innerHTML,
-    error_message_template = Handlebars.compile(error_message_source);
+    error_message_template = Handlebars.compile(error_message_source),
+    variable = {};
 
 
-  function renderListboxThead(gadget, template, head_value) {
+  function renderListboxThead(gadget, template) {
     return gadget.translateHtml(template({
       head_value: gadget.props.head_value,
       show_anchor: gadget.state.show_anchor,
@@ -189,7 +190,8 @@
         field_json = options.field_json,
         i,
         sort_column_list = [],
-        search_column_list = [];
+        search_column_list = [],
+        queue;
 
       //only display which is in listbox's column list
       if (field_json.sort_column_list.length) {
@@ -215,7 +217,21 @@
       }
       search_column_list.push(["searchable_text", "Searchable Text"]);
 
-      return RSVP.Queue()
+      queue = RSVP.Queue();
+      if (!variable.translated_records) {
+        queue
+          .push(function () {
+            return RSVP.all([
+              gadget.translate('Records'),
+              gadget.translate('No records')
+            ]);
+          })
+          .push(function (results) {
+            variable.translated_records = results[0];
+            variable.translated_no_record = results[1];
+          });
+      }
+      queue
         .push(function () {
           // Cancel previous line rendering to not conflict with the asynchronous render for now
           return gadget.renderContent(true);
@@ -258,6 +274,7 @@
           // Force line calculation in any case
           return gadget.renderContent();
         });
+      return queue;
     })
 
     .onStateChange(function () {
@@ -467,11 +484,11 @@
               foot.next_classname = "ui-btn ui-icon-carat-r ui-btn-icon-right responsive ui-last-child";
               foot.next_url = url_list[1];
               if ((begin_from === 0) && (counter === 0)) {
-                foot.record = "No records";
+                foot.record = variable.translated_no_record;
               } else if ((dataset.data.rows.length <= lines) && (begin_from === 0)) {
-                foot.record = counter + " Records";
+                foot.record = counter + " " + variable.translated_records;
               } else {
-                foot.record = "Records " + (((begin_from + lines) / lines - 1) * lines + 1) + " - " + (((begin_from + lines) / lines - 1) * lines + counter);
+                foot.record = variable.translated_records + "  " + (((begin_from + lines) / lines - 1) * lines + 1) + " - " + (((begin_from + lines) / lines - 1) * lines + counter);
               }
 
               if (begin_from === 0) {
@@ -649,4 +666,4 @@
     });
 
 }(window, document, rJS, URI, RSVP,
-  SimpleQuery, ComplexQuery, Query, Handlebars, console, QueryFactory));
\ No newline at end of file
+  SimpleQuery, ComplexQuery, Query, Handlebars, console, QueryFactory));
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml
index ea2ef2dd19..89e5d7b600 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.47559.38051.59921</string> </value>
+                <value> <string>955.20594.58985.30890</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476976330.15</float>
+                        <float>1479290108.34</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.js
index 55f82a11ec..3be80c24c6 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.js
@@ -23,6 +23,7 @@
           url: gadget.state.url,
           allow_creation: gadget.state.allow_creation,
           portal_types: gadget.state.portal_types,
+          translated_portal_types: gadget.state.translated_portal_types,
           value_relative_url: value_relative_url,
           value_text: value_text,
           value_uid: value_uid,
@@ -55,6 +56,7 @@
           url: field_json.url,
           allow_creation: field_json.allow_creation,
           portal_types: field_json.portal_types,
+	  translated_portal_types: field_json.translated_portal_types,
           relation_field_id: field_json.relation_field_id,
           hidden: field_json.hidden
         };
@@ -233,4 +235,4 @@
       return final_result;
     });
 
-}(window, rJS, RSVP, document));
\ No newline at end of file
+}(window, rJS, RSVP, document));
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.xml
index 42d4ea77ff..1e2ceb6089 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_multirelationstringfield_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.7644.28099.443</string> </value>
+                <value> <string>955.20651.19230.8738</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1479375486.58</float>
+                        <float>1479293669.46</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.js
index 7a413728e8..b53f84cec9 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.js
@@ -47,7 +47,7 @@
           }
           return gadget.jio_allDocs({
             query: Query.objectToSearchText(new ComplexQuery({operator: 'OR', query_list: query_list})),
-            select_list: ["title", "portal_type"],
+            select_list: ["title", "translated_portal_type"],
             limit: id_list.length
           });
         })
@@ -72,7 +72,7 @@
           for (i = 0; i < result_list.length; i += 1) {
             document_dict[result_list[i][2]] = {
               link: result_list[i][0],
-              title: (result_list[i][1].title || result_list[i][2]) + " (" + result_list[i][1].portal_type + ")"
+              title: (result_list[i][1].title || result_list[i][2]) + " (" + result_list[i][1].translated_portal_type + ")"
             };
           }
           // Sort by access time
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.xml
index b21334b8e6..3c3eb7e5c1 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_history_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.45675.44850.53452</string> </value>
+                <value> <string>953.52380.29788.47923</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476952911.66</float>
+                        <float>1473419443.85</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.js
index c1991216c6..25849bbee7 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.js
@@ -50,6 +50,7 @@
     .declareAcquiredMethod("getUrlFor", "getUrlFor")
     .declareAcquiredMethod("redirect", "redirect")
     .declareAcquiredMethod("jio_getAttachment", "jio_getAttachment")
+    .declareAcquiredMethod("translateHtml", "translateHtml")
 
     /////////////////////////////////////////////////////////////////
     // declared methods
@@ -120,6 +121,12 @@
               ]]
             }
           });
+        })
+        .push(function () {
+          return gadget.translateHtml(gadget.props.element.querySelector(".left").innerHTML);
+        })
+        .push(function (html) {
+          gadget.props.element.querySelector(".left").innerHTML = html;
         });
     })
     .declareMethod("triggerSubmit", function () {
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.xml
index 20cf540ee1..1745df26d5 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_relation_search_js.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.27036.35871.42001</string> </value>
+                <value> <string>954.5791.20424.25736</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1475744573.87</float>
+                        <float>1474556136.49</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.html
index d7b75ef6f7..420a407ddd 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.html
@@ -1,5 +1,11 @@
 <!DOCTYPE html>
 <html>
+  <!--
+    data-i18n=Type
+    data-i18n=Reference
+    data-i18n=Description
+    data-i18n=State
+  -->
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.xml
index 320d8ac9be..46aef5fc21 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_search_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>950.28765.38539.13653</string> </value>
+                <value> <string>953.56663.27739.23483</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1460378755.69</float>
+                        <float>1474563707.59</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.html
index d45b35ff91..6d7a546249 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.html
@@ -1,5 +1,8 @@
 <!DOCTYPE html>
 <html>
+<!--
+  data-i18n=Worklist
+-->
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.xml
index b971acce01..0fbbf2ee3c 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.45675.44850.53452</string> </value>
+                <value> <string>953.56732.44606.43468</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476955713.49</float>
+                        <float>1474556302.46</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.js
index 50a408d0d8..b7464e7169 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.js
@@ -61,7 +61,7 @@
                 view: 'view'
               }}),
               // Remove the counter from the title
-              action_list[i].name.replace(/ \(\d+\)$/, ''),
+              action_list[i].name,
               action_list[i].count
             ]));
 
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.xml
index 1a3d1495aa..3a63f7eff5 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_page_worklist_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.47218.14887.48486</string> </value>
+                <value> <string>949.45349.17509.30190</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476956693.83</float>
+                        <float>1473173906.59</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.html
index a6f1bdeb69..de67c5ffe8 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.html
@@ -36,7 +36,7 @@
           <li><a href="{{module_href}}" class="ui-btn ui-btn-icon-left ui-icon-puzzle-piece" data-i18n="Modules" accesskey="m">Modules</a></li>
           <li><a href="{{worklist_href}}" class="ui-btn ui-btn-icon-left ui-icon-clipboard" data-i18n="Worklists" accesskey="w">Worklists</a></li>
           <li><a href="{{history_href}}" class="ui-btn ui-btn-icon-left ui-icon-history" data-i18n="History" accesskey="h">History</a></li>
-          <li><a href="{{search_href}}" class="ui-btn ui-btn-icon-left ui-icon-search" data-i18n="History" accesskey="s">Search</a></li>
+          <li><a href="{{search_href}}" class="ui-btn ui-btn-icon-left ui-icon-search" data-i18n="Search" accesskey="s">Search</a></li>
           <li><a href="{{preference_href}}" class="ui-btn ui-btn-icon-left ui-icon-gear" data-i18n="Preference">Preferences</a></li>
           <!--div>
           {{#if language_list}}
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.xml
index 195150543a..b32bc9238d 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.14137.61057.25617</string> </value>
+                <value> <string>953.6580.58198.13568</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1467279122.77</float>
+                        <float>1473162224.39</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.js
index 92a5f85d05..f3b60a13a9 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.js
@@ -78,7 +78,7 @@
             "search_href": all_result[4],
             "worklist_href": all_result[5]
           });
-          return tmp;
+          return g.translateHtml(tmp);
         })
         .push(function (my_translated_or_plain_html) {
           g.props.element.querySelector("div").innerHTML = my_translated_or_plain_html;
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.xml
index da995c500c..cf1d002f55 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_panel_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.1507.19232.15035</string> </value>
+                <value> <string>953.6580.58198.13568</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1466524414.0</float>
+                        <float>1473161369.59</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.html
index 75c4d4a0e6..987cb325eb 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.html
@@ -1,6 +1,10 @@
 <!DOCTYPE html>
 <html>
   <head>
+    <!--
+      data-i18n=Workflow-Transitions
+      data-i18n=Actions
+    -->
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
     <title>ERP5 Page Action</title>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.xml
index a87a1bad7f..42649f4bfa 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_actionpage_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>949.53789.19765.27784</string> </value>
+                <value> <string>953.48219.30595.27340</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1460378795.97</float>
+                        <float>1474556323.96</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.html
index 43168fe00e..39fe046750 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.html
@@ -1,5 +1,8 @@
 <!DOCTYPE html>
 <html>
+  <!--
+    data-i18n=Title
+  -->
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.xml
index 920c2973b2..08fd250dae 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.43255.60632.47035</string> </value>
+                <value> <string>954.5909.42680.32921</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1468942516.97</float>
+                        <float>1474563730.2</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.js
index 3625f02682..6b3bb276ad 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.js
@@ -52,8 +52,7 @@
         })
         .push(function (form_gadget) {
           var column_list = [
-            ['title', 'Title']
-          ];
+            ['translated_title', 'Title']];
           return form_gadget.render({
             erp5_document: {"_embedded": {"_view": {
               "listbox": {
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.xml
index 8c9313c0bf..06fd11ca06 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_frontpage_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.64761.25287.18397</string> </value>
+                <value> <string>954.44756.57059.6894</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1475244399.84</float>
+                        <float>1476893530.25</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.html
index bdf4ba0a86..0f3c03b516 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.html
@@ -1,5 +1,9 @@
 <!DOCTYPE html>
 <html>
+ <!--
+   data-i18n=User
+   data-i18n=Language
+ -->
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
@@ -12,10 +16,17 @@
     <!-- custom script -->
     <script src="gadget_erp5_page_preference.js" type="text/javascript"></script>
 
-  </head>
-  <body>
 
-  Who are you?
 
+  </head>
+  <body>
+    <form class="preference">
+      <button type="submit" class="ui-btn ui-btn-b ui-btn-inline
+        ui-icon-edit ui-btn-icon-right ui-screen-hidden"></button>
+      <div data-gadget-url="gadget_erp5_form.html"
+          data-gadget-scope="erp5_form"
+          data-gadget-sandbox="public">
+      </div>
+    </form>
   </body>
 </html>
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.xml
index c4a2776cbe..9696eb4189 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.45675.44850.53452</string> </value>
+                <value> <string>953.6663.63367.11298</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476958219.29</float>
+                        <float>1473246353.73</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.js
index 1db0241805..b6b364bfd0 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.js
@@ -1,6 +1,6 @@
-/*global window, rJS */
+/*global window, rJS, RSVP */
 /*jslint indent: 2, maxerr: 3 */
-(function (window, rJS) {
+(function (window, rJS, RSVP) {
   "use strict";
 
   rJS(window)
@@ -8,22 +8,30 @@
     // handle acquisition
     /////////////////////////////////////////////////////////////////
     .declareAcquiredMethod("updateHeader", "updateHeader")
-    .declareAcquiredMethod("translateHtml", "translateHtml")
+    .declareAcquiredMethod("translate", "translate")
     .declareAcquiredMethod("getSetting", "getSetting")
+    .declareAcquiredMethod("setSetting", "setSetting")
     .declareAcquiredMethod("jio_get", "jio_get")
     .declareAcquiredMethod("jio_allDocs", "jio_allDocs")
+    .declareAcquiredMethod("notifySubmitting", "notifySubmitting")
+    .declareAcquiredMethod("notifySubmitted", "notifySubmitted")
+    .declareAcquiredMethod("redirect", "redirect")
 
     /////////////////////////////////////////////////////////////////
     // declared methods
     /////////////////////////////////////////////////////////////////
     .declareMethod("render", function () {
-      var gadget = this;
-
-      // XXX: Lot of DOM touches
+      var gadget = this,
+        user = "Who are you?";
       return gadget.updateHeader({
-        page_title: 'Preference'
+        page_title: 'Preference',
+        save_action: true
       })
         .push(function () {
+          return gadget.getDeclaredGadget("erp5_form");
+        })
+        .push(function (erp5_form) {
+          gadget.state.erp5_form = erp5_form;
           return gadget.getSetting('me');
         })
         .push(function (me) {
@@ -33,17 +41,89 @@
               select_list: ['title']
             })
               .push(function (result) {
-                gadget.element.textContent = result.data.rows[0].value.title;
+                user = result.data.rows[0].value.title;
               });
           }
-          // gadget.props.element.textContent = me;
         })
         .push(function () {
-          return gadget.translateHtml(gadget.element.innerHTML);
+          return RSVP.all([
+            gadget.getSetting("language_map"),
+            gadget.getSetting("selected_language"),
+            gadget.getSetting("default_selected_language"),
+            gadget.translate("User"),
+            gadget.translate("Language")
+            
+          ]);
         })
-        .push(function (my_translated_html) {
-          gadget.element.innerHTML = my_translated_html;
+        .push(function (results) {
+          var selected_language = results[1] || results[2],
+            key,
+            list_item = [],
+            options = JSON.parse(results[0]);
+          gadget.state.old_selected_lang = selected_language;
+          for (key in options) {
+            if (options.hasOwnProperty(key)) {
+              list_item.push([options[key], key]);
+            }
+          }
+          return gadget.state.erp5_form.render({
+            erp5_document: {"_embedded": {"_view": {
+              'User': {
+                "default": user,
+                "editable": 0,
+                "key": "field_user",
+                "title": results[3],
+                "type": "StringField"
+              },
+              'Language': {
+                "default": selected_language,
+                "editable": 1,
+                "items": list_item,
+                "key": "field_language",
+                "title": results[4],
+                "type": "ListField"
+              }
+            }},
+              "_links": {
+                "type": {
+                  // form_list display portal_type in header
+                  name: ""
+                }
+              }
+              },
+            form_definition: {
+              group_list: [[
+                "left",
+                [["User"], ["Language"]]
+              ]]
+            }
+          });
+        });
+    })
+    .declareMethod('triggerSubmit', function () {
+      this.element.querySelector('button').click();
+    })
+    .onEvent('submit', function () {
+      var gadget = this,
+        selected_lang;
+      return gadget.notifySubmitting()
+        .push(function () {
+          return gadget.state.erp5_form.getContent();
+        })
+        .push(function (data) {
+          selected_lang = data.field_language;
+          return gadget.setSetting("selected_language", selected_lang);
+        })
+        .push(function () {
+          if (gadget.state.old_selected_lang !== selected_lang) {
+            return gadget.redirect({
+              command: 'change_language',
+              options: {
+                language: selected_lang
+              }
+            });
+          }
+          return gadget.notifySubmitted();
         });
-
     });
-}(window, rJS));
\ No newline at end of file
+}(window, rJS, RSVP));
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.xml
index fc6bfd855d..e29579c116 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_preferencepage_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.47266.11723.40516</string> </value>
+                <value> <string>955.20539.55071.38980</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1476958263.79</float>
+                        <float>1479302491.62</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.html
index 1328449419..e741fb866e 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.html
@@ -1,5 +1,9 @@
 <!DOCTYPE html>
 <html>
+  <!--
+    data-i18n=Jumps
+    data-i18n=Breadcrumb
+  -->
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.xml
index e5ccbf29eb..5a056f5bf4 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_tabpage_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>946.44927.40202.16725</string> </value>
+                <value> <string>953.49748.33034.5700</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1460379644.0</float>
+                        <float>1474563753.89</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.html
index 0164b7e7af..d8c6f9d5b0 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.html
@@ -34,15 +34,17 @@
           <li class="ui-li-static ui-body-inherit ui-icon-mail-forward ui-btn-icon-right" data-relative-url="{{id}}" data-uid="{{uid}}">{{value}}</li>
         {{/each}}
         {{#each type}}
-         <li class="ui-li-static ui-body-inherit ui-bar-inherit ui-icon-plus ui-btn-icon-right" data-create-object="{{this}}" name="{{this}}">Create New {{this}}: {{../value}}</li>
+         <li class="ui-li-static ui-body-inherit ui-bar-inherit ui-icon-plus ui-btn-icon-right" data-i18n="Create New" data-create-object="{{value}}" name="{{name}}">Create New
+           <span data-create-object="{{value}}"> {{name}}: {{../value}}</span></li>
         {{/each}}
       {{else}}
         <!--li class="ui-autocomplete ui-li ui-li-divider ui-bar-inherit ui-first-child" role="heading">No result</li-->
         {{#each type}}
-         <li class="ui-li-static ui-body-inherit ui-bar-inherit ui-icon-plus ui-btn-icon-right" data-create-object="{{this}}" name="{{this}}">Create New {{this}}: {{../value}}</li>
+         <li class="ui-li-static ui-body-inherit ui-bar-inherit ui-icon-plus ui-btn-icon-right" data-i18n="Create New" data-create-object="{{value}}" name="{{name}}">Create New
+           <span data-create-object="{{value}}">{{name}}: {{../value}}</span></li>
         {{/each}}
       {{/if}}
-      <li class="ui-li-static ui-body-inherit ui-last-child ui-bar-inherit ui-icon-search ui-btn-icon-right" data-explore=true >Explore the Search Result List</li>
+      <li class="ui-li-static ui-body-inherit ui-last-child ui-bar-inherit ui-icon-search ui-btn-icon-right" data-explore=true data-i18n="Explore the Search Result List" >Explore the Search Result List</li>
     </script>
 
   </head>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.xml
index 6283c87106..542eb463bb 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.7622.39581.2525</string> </value>
+                <value> <string>954.5712.44925.37444</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1478511768.91</float>
+                        <float>1474553624.23</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.js
index bf8e4e0188..51ebbf1471 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.js
@@ -86,6 +86,7 @@
         url: options.url,
         allow_creation: options.allow_creation,
         portal_types: options.portal_types,
+        translated_portal_types: options.translated_portal_types,
         has_focus: false,
         relation_index: options.relation_index,
         value_relative_url: options.value_relative_url,
@@ -235,11 +236,14 @@
             .push(function (result) {
               var list = [],
                 i,
-                type;
-              if (gadget.state.allow_creation) {
-                type = gadget.state.portal_types;
-              } else {
                 type = [];
+              if (gadget.state.allow_creation) {
+                for (i = 0; i < gadget.state.portal_types.length; i += 1) {
+                  type.push({
+                    name: gadget.state.translated_portal_types[i],
+                    value: gadget.state.portal_types[i]
+                  });
+                }
               }
               for (i = 0; i < result.data.rows.length; i += 1) {
                 list.push({
@@ -249,11 +253,14 @@
                 });
               }
               plane.className = JUMP_UNKNOWN_CLASS_STR;
-              ul.innerHTML = relation_listview_template({
+              return gadget.translateHtml(relation_listview_template({
                 list: list,
                 type: type,
                 value: value_text
-              });
+              }));
+            })
+            .push(function (html) {
+              ul.innerHTML = html;
             });
         });
 
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.xml
index e5a4796312..6bb91ef764 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relation_input_js.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.17976.26191.30156</string> </value>
+                <value> <string>955.20665.33421.35549</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1479133107.47</float>
+                        <float>1479294380.88</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.js
index 529375b407..cf857bd88d 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.js
@@ -24,6 +24,7 @@
             url: field_json.url,
             allow_creation: field_json.allow_creation,
             portal_types: field_json.portal_types,
+            translated_portal_types: field_json.translated_portal_types,
             value_relative_url: field_json.relation_item_relative_url[0],
             relation_index: 0,
             hidden: field_json.hidden
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.xml
index cc2c1118fa..2aace219a3 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_relationstringfield_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>955.7643.7350.21333</string> </value>
+                <value> <string>955.18006.50413.2645</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1479375314.48</float>
+                        <float>1479293469.27</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.js
index bdb5804327..b1922409bb 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.js
@@ -27,6 +27,8 @@
     COMMAND_SELECTION_NEXT = "selection_next",
     COMMAND_HISTORY_PREVIOUS = "history_previous",
     COMMAND_PUSH_HISTORY = "push_history",
+    COMMAND_CHANGE_LANGUAGE = "change_language",
+    REDIRECT_TIMEOUT = 5055,
     VALID_URL_COMMAND_DICT = {};
   VALID_URL_COMMAND_DICT[COMMAND_DISPLAY_STATE] = null;
   VALID_URL_COMMAND_DICT[COMMAND_DISPLAY_STORED_STATE] = null;
@@ -40,6 +42,7 @@
   VALID_URL_COMMAND_DICT[COMMAND_LOGIN] = null;
   VALID_URL_COMMAND_DICT[COMMAND_RAW] = null;
   VALID_URL_COMMAND_DICT[COMMAND_RELOAD] = null;
+  VALID_URL_COMMAND_DICT[COMMAND_CHANGE_LANGUAGE] = null;
 
 
   function endsWith(str, suffix) {
@@ -108,6 +111,20 @@
     if (command === COMMAND_RAW) {
       return options.url;
     }
+    if (command === COMMAND_CHANGE_LANGUAGE) {
+      return new RSVP.Queue()
+        .push(function () {
+          return gadget.getSetting("website_url_set");
+        })
+        .push(function (result) {
+          var param_list =  window.location.hash.split('#')[1],
+            new_url = JSON.parse(result)[options.language];
+          if (param_list) {
+            new_url += '#' + param_list;
+          }
+          return new_url;
+        });
+    }
     var result = "#" + PREFIX_COMMAND + (command || ""),
       prefix = "?",
       key,
@@ -858,7 +875,33 @@
     })
 
     .declareMethod('start', function () {
-      this.props.start_deferred.resolve();
+      var gadget = this;
+      return new RSVP.Queue()
+        .push(function () {
+          return RSVP.all([
+            gadget.getSetting("selected_language"),
+            gadget.getSetting("default_selected_language")
+          ]);
+        })
+        .push(function (results) {
+          if (results[1] !== results[0] && results[0]) {
+            return gadget.redirect({
+              command: 'change_language',
+              options: {
+                language: results[0]
+              }
+            });
+          }
+        })
+        .push(function () {
+          gadget.props.start_deferred.resolve();
+        })
+        .push(undefined, function (error) {
+          if (error instanceof RSVP.CancellationError) {
+            return;
+          }
+          throw error;
+        });
     })
 
     .declareAcquiredMethod('renderApplication', 'renderApplication')
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.xml
index 46a9c0255b..fdd19851be 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_router_js.xml
@@ -232,7 +232,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>954.57620.63396.46779</string> </value>
+                <value> <string>955.20572.17338.63419</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -250,7 +250,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1477580291.06</float>
+                        <float>1479288846.05</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.html
index 607d839f68..704e2798f7 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.html
@@ -1,5 +1,18 @@
 <!DOCTYPE html>
 <html>
+  <!--
+    data-i18n=All criterions (AND)
+    data-i18n=At least one (OR)
+    data-i18n=Exact Match
+    data-i18n=keyword
+    data-i18n=Contain
+    data-i18n=Equals To
+    data-i18n=Greater Than
+    data-i18n=Less Than
+    data-i18n=Not Greater Than
+    data-i18n=Not Less Than
+    data-i18n=Searchable Text
+  -->
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, user-scalable=no" />
@@ -83,7 +96,7 @@
           <fieldset class="ui-controlgroup ui-corner-all">
             <select data-iconpos="left" name="heard_about">
               <option data-i18n="All criterions (AND)" value="AND">All criterions (AND)</option>
-              <option data-i18n="At lease one (OR)" value="OR">At lease one (OR)</option>
+              <option data-i18n="At least one (OR)" value="OR">At least one (OR)</option>
             </select>
            </fieldset>
          
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.xml
index d9e8ecc792..7d54cc0b3a 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_searcheditor_html.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>952.34496.35921.52275</string> </value>
+                <value> <string>954.7210.40753.48042</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1468414694.8</float>
+                        <float>1474905528.91</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.html b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.html
index 4d440c4485..9cdef81989 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.html
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.html
@@ -9,7 +9,6 @@
     <script src="rsvp.js" type="text/javascript"></script>
     <script src="renderjs.js" type="text/javascript"></script>
 
-    <script src="i18next.js"></script>
     <!-- custom script -->
     <script src="gadget_translation_data.js" type="text/javascript"></script>
     <script src="gadget_translation.js" type="text/javascript"></script>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.xml
index 33a61ff14a..cc1dc604a1 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_html.xml
@@ -224,7 +224,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>romain</string> </value>
+                <value> <string>zope</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -238,7 +238,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>945.43799.10287.64221</string> </value>
+                <value> <string>949.45349.17509.30190</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -256,8 +256,8 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1445935119.77</float>
-                        <string>GMT</string>
+                        <float>1467132987.54</float>
+                        <string>UTC</string>
                       </tuple>
                     </state>
                   </object>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.js
index 2b47883faf..e403d3b8df 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.js
@@ -1,116 +1,132 @@
-/*global document, window, rJS, translation_data */
+/*global document, window, rJS, translation_data, RSVP */
 /*jslint nomen: true, indent: 2 */
-(function (document, window, rJS, translation_data) {
+(function (document, window, rJS, translation_data, RSVP) {
   "use strict";
 
-  function translate(string) {
-    // XXX i18n.t
-    return translation_data.en[string] || string;
+  function translate(string, gadget) {
+    return translation_data[gadget.state.language][string] || string;
   }
 
-  rJS(window)
-
-    /////////////////////////////////////////////////////////////////
-    // ready
-    /////////////////////////////////////////////////////////////////
-    .ready(function (gadget) {
-      gadget.property_dict = {};
-    })
-
-    .declareMethod('translate', function (string) {
-      // XXX Allow to change the language
-      return translate(string);
-    })
+  // translate a list of elements passed and returned as string
+  function translateHtml(string, gadget) {
+    var temp, element_list, i, i_len, element, lookup, translate_list, target,
+      route_text, has_breaks, l, l_len, j, j_len;
+    // NOTE: <div> cannot be used for everything... (like table rows)
+    // XXX: currently I only update where needed. Eventually all calls to
+    // translateHtml should pass "their" proper wrapping element
+    temp = document.createElement("div");
+    temp.innerHTML = string;
 
-    // translate a list of elements passed and returned as string
-    .declareMethod('translateHtml', function (my_string) {
-      var temp, element_list, i, i_len, element, lookup, translate_list, target,
-        route_text, has_breaks, l, l_len, gadget, j, j_len;
+    element_list = temp.querySelectorAll("[data-i18n]");
 
-      gadget = this;
+    for (i = 0, i_len = element_list.length; i < i_len; i += 1) {
+      element = element_list[i];
+      lookup = element.getAttribute("data-i18n");
 
-      // skip if no translations available
-      if (gadget.property_dict.translation_disabled) {
-        return my_string;
-      }
-
-      // NOTE: <div> cannot be used for everything... (like table rows)
-      // XXX: currently I only update where needed. Eventually all calls to
-      // translateHtml should pass "their" proper wrapping element
-      temp = document.createElement("div");
-      temp.innerHTML = my_string;
-
-      element_list = temp.querySelectorAll("[data-i18n]");
-
-      for (i = 0, i_len = element_list.length; i < i_len; i += 1) {
-        element = element_list[i];
-        lookup = element.getAttribute("data-i18n");
+      if (lookup) {
+        translate_list = lookup.split(";");
 
-        if (lookup) {
-          translate_list = lookup.split(";");
+        for (l = 0, l_len = translate_list.length; l < l_len; l += 1) {
+          target = translate_list[l].split("]");
 
-          for (l = 0, l_len = translate_list.length; l < l_len; l += 1) {
-            target = translate_list[l].split("]");
+          switch (target[0]) {
+          case "[placeholder":
+          case "[alt":
+          case "[title":
+            element.setAttribute(target[0].substr(1), translate(target[1], gadget));
+            break;
+          case "[value":
+            has_breaks = element.previousSibling.textContent.match(/\n/g);
 
-            switch (target[0]) {
-            case "[placeholder":
-            case "[alt":
-            case "[title":
-              element.setAttribute(target[0].substr(1), translate(target[1]));
-              break;
-            case "[value":
-              has_breaks = element.previousSibling.textContent.match(/\n/g);
-
-              // JQM inputs > this avoids calling checkboxRadio("refresh")!
-              if (element.tagName === "INPUT") {
-                switch (element.type) {
-                case "submit":
-                case "reset":
-                case "button":
-                  route_text = true;
-                  break;
-                }
-              }
-              if (route_text && (has_breaks || []).length === 0) {
-                element.previousSibling.textContent = translate(target[1]);
+            // JQM inputs > this avoids calling checkboxRadio("refresh")!
+            if (element.tagName === "INPUT") {
+              switch (element.type) {
+              case "submit":
+              case "reset":
+              case "button":
+                route_text = true;
+                break;
               }
-              element.value = translate(target[1]);
-              break;
-            case "[parent":
-              element.parentNode.childNodes[0].textContent =
-                  translate(target[1]);
-              break;
-            case "[node":
-              element.childNodes[0].textContent = translate(target[1]);
-              break;
-            case "[last":
-              // if null, append, if textnode replace, if span, appned
-              if (element.lastChild && element.lastChild.nodeType === 3) {
-                element.lastChild.textContent = translate(target[1]);
-              } else {
-                element.appendChild(document.createTextNode(translate(target[1])));
-              }
-              break;
-            case "[html":
-              element.innerHTML = translate(target[1]);
-              break;
-            default:
-              if (element.hasChildNodes()) {
-                for (j = 0, j_len = element.childNodes.length; j < j_len; j += 1) {
-                  if (element.childNodes[j].nodeType === 3) {
-                    element.childNodes[j].textContent = translate(translate_list[l]);
-                  }
+            }
+            if (route_text && (has_breaks || []).length === 0) {
+              element.previousSibling.textContent = translate(target[1], gadget);
+            }
+            element.value = translate(target[1], gadget);
+            break;
+          case "[parent":
+            element.parentNode.childNodes[0].textContent =
+                translate(target[1], gadget);
+            break;
+          case "[node":
+            element.childNodes[0].textContent = translate(target[1], gadget);
+            break;
+          case "[last":
+            // if null, append, if textnode replace, if span, appned
+            if (element.lastChild && element.lastChild.nodeType === 3) {
+              element.lastChild.textContent = translate(target[1], gadget);
+            } else {
+              element.appendChild(document.createTextNode(translate(target[1], gadget)));
+            }
+            break;
+          case "[html":
+            element.innerHTML = translate(target[1], gadget);
+            break;
+          default:
+            if (element.hasChildNodes()) {
+              for (j = 0, j_len = element.childNodes.length; j < j_len; j += 1) {
+                if (element.childNodes[j].nodeType === 3) {
+                  element.childNodes[j].textContent = translate(translate_list[l], gadget);
                 }
-              } else {
-                element.textContent = translate(translate_list[l]);
               }
-              break;
+            } else {
+              element.textContent = translate(translate_list[l], gadget);
             }
+            break;
           }
         }
       }
-      // return string
-      return temp.innerHTML;
+    }
+    // return string
+    return temp.innerHTML;
+  }
+
+  rJS(window)
+    .declareAcquiredMethod("getSetting", "getSetting")
+    .declareMethod('translate', function (string) {
+      // XXX Allow to change the language
+      var gadget = this;
+      if (!gadget.state.language) {
+        return new RSVP.Queue()
+          .push(function () {
+            return RSVP.all([
+              gadget.getSetting("selected_language"),
+              gadget.getSetting("default_selected_language")
+            ]);
+          })
+          .push(function (results) {
+            gadget.state.language = results[0] || results[1];
+            return translate(string, gadget);
+          });
+      }
+      return translate(string, gadget);
+    })
+
+    .declareMethod('translateHtml', function (string) {
+      var gadget = this;
+      if (!gadget.state.language) {
+        return new RSVP.Queue()
+          .push(function () {
+            return RSVP.all([
+              gadget.getSetting("selected_language"),
+              gadget.getSetting("default_selected_language")
+            ]);
+          })
+          .push(function (results) {
+            gadget.state.language = results[0] || results[1];
+            return translateHtml(string, gadget);
+          });
+      }
+      return translateHtml(string, gadget);
     });
 
-}(document, window, rJS, translation_data));
+}(document, window, rJS, translation_data, RSVP));
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.xml
index aed2fdcd8e..bcfdf5cf5b 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_translation_js.xml
@@ -234,7 +234,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>948.17388.42239.34542</string> </value>
+                <value> <string>955.18006.50413.2645</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -252,7 +252,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1452009218.06</float>
+                        <float>1479302155.8</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.js
deleted file mode 100644
index 7e678fce80..0000000000
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.js
+++ /dev/null
@@ -1,2889 +0,0 @@
-// i18next, v1.7.4
-// Copyright (c)2014 Jan M眉hlemann (jamuhl).
-// Distributed under MIT license
-// http://i18next.com
-(function() {
-
-    // add indexOf to non ECMA-262 standard compliant browsers
-    if (!Array.prototype.indexOf) {
-        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
-            "use strict";
-            if (this == null) {
-                throw new TypeError();
-            }
-            var t = Object(this);
-            var len = t.length >>> 0;
-            if (len === 0) {
-                return -1;
-            }
-            var n = 0;
-            if (arguments.length > 0) {
-                n = Number(arguments[1]);
-                if (n != n) { // shortcut for verifying if it's NaN
-                    n = 0;
-                } else if (n != 0 && n != Infinity && n != -Infinity) {
-                    n = (n > 0 || -1) * Math.floor(Math.abs(n));
-                }
-            }
-            if (n >= len) {
-                return -1;
-            }
-            var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
-            for (; k < len; k++) {
-                if (k in t && t[k] === searchElement) {
-                    return k;
-                }
-            }
-            return -1;
-        }
-    }
-    
-    // add lastIndexOf to non ECMA-262 standard compliant browsers
-    if (!Array.prototype.lastIndexOf) {
-        Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
-            "use strict";
-            if (this == null) {
-                throw new TypeError();
-            }
-            var t = Object(this);
-            var len = t.length >>> 0;
-            if (len === 0) {
-                return -1;
-            }
-            var n = len;
-            if (arguments.length > 1) {
-                n = Number(arguments[1]);
-                if (n != n) {
-                    n = 0;
-                } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
-                    n = (n > 0 || -1) * Math.floor(Math.abs(n));
-                }
-            }
-            var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
-            for (; k >= 0; k--) {
-                if (k in t && t[k] === searchElement) {
-                    return k;
-                }
-            }
-            return -1;
-        };
-    }
-    
-    // Add string trim for IE8.
-    if (typeof String.prototype.trim !== 'function') {
-        String.prototype.trim = function() {
-            return this.replace(/^\s+|\s+$/g, ''); 
-        }
-    }
-
-    var root = this
-      , $ = root.jQuery || root.Zepto
-      , i18n = {}
-      , resStore = {}
-      , currentLng
-      , replacementCounter = 0
-      , languages = []
-      , initialized = false
-      , sync = {};
-
-
-
-    // Export the i18next object for **CommonJS**. 
-    // If we're not in CommonJS, add `i18n` to the
-    // global object or to jquery.
-    if (typeof module !== 'undefined' && module.exports) {
-        if (!$) {
-          try {
-            $ = require('jquery');
-          } catch(e) {
-            // just ignore
-          }
-        }
-        if ($) {
-            $.i18n = $.i18n || i18n;
-        }
-        module.exports = i18n;
-    } else {
-        if ($) {
-            $.i18n = $.i18n || i18n;
-        }
-        
-        root.i18n = root.i18n || i18n;
-    }
-    sync = {
-    
-        load: function(lngs, options, cb) {
-            if (options.useLocalStorage) {
-                sync._loadLocal(lngs, options, function(err, store) {
-                    var missingLngs = [];
-                    for (var i = 0, len = lngs.length; i < len; i++) {
-                        if (!store[lngs[i]]) missingLngs.push(lngs[i]);
-                    }
-    
-                    if (missingLngs.length > 0) {
-                        sync._fetch(missingLngs, options, function(err, fetched) {
-                            f.extend(store, fetched);
-                            sync._storeLocal(fetched);
-    
-                            cb(null, store);
-                        });
-                    } else {
-                        cb(null, store);
-                    }
-                });
-            } else {
-                sync._fetch(lngs, options, function(err, store){
-                    cb(null, store);
-                });
-            }
-        },
-    
-        _loadLocal: function(lngs, options, cb) {
-            var store = {}
-              , nowMS = new Date().getTime();
-    
-            if(window.localStorage) {
-    
-                var todo = lngs.length;
-    
-                f.each(lngs, function(key, lng) {
-                    var local = window.localStorage.getItem('res_' + lng);
-    
-                    if (local) {
-                        local = JSON.parse(local);
-    
-                        if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
-                            store[lng] = local;
-                        }
-                    }
-    
-                    todo--; // wait for all done befor callback
-                    if (todo === 0) cb(null, store);
-                });
-            }
-        },
-    
-        _storeLocal: function(store) {
-            if(window.localStorage) {
-                for (var m in store) {
-                    store[m].i18nStamp = new Date().getTime();
-                    window.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
-                }
-            }
-            return;
-        },
-    
-        _fetch: function(lngs, options, cb) {
-            var ns = options.ns
-              , store = {};
-            
-            if (!options.dynamicLoad) {
-                var todo = ns.namespaces.length * lngs.length
-                  , errors;
-    
-                // load each file individual
-                f.each(ns.namespaces, function(nsIndex, nsValue) {
-                    f.each(lngs, function(lngIndex, lngValue) {
-                        
-                        // Call this once our translation has returned.
-                        var loadComplete = function(err, data) {
-                            if (err) {
-                                errors = errors || [];
-                                errors.push(err);
-                            }
-                            store[lngValue] = store[lngValue] || {};
-                            store[lngValue][nsValue] = data;
-    
-                            todo--; // wait for all done befor callback
-                            if (todo === 0) cb(errors, store);
-                        };
-                        
-                        if(typeof options.customLoad == 'function'){
-                            // Use the specified custom callback.
-                            options.customLoad(lngValue, nsValue, options, loadComplete);
-                        } else {
-                            //~ // Use our inbuilt sync.
-                            sync._fetchOne(lngValue, nsValue, options, loadComplete);
-                        }
-                    });
-                });
-            } else {
-                // Call this once our translation has returned.
-                var loadComplete = function(err, data) {
-                    cb(null, data);
-                };
-    
-                if(typeof options.customLoad == 'function'){
-                    // Use the specified custom callback.
-                    options.customLoad(lngs, ns.namespaces, options, loadComplete);
-                } else {
-                    var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
-                    // load all needed stuff once
-                    f.ajax({
-                        url: url,
-                        success: function(data, status, xhr) {
-                            f.log('loaded: ' + url);
-                            loadComplete(null, data);
-                        },
-                        error : function(xhr, status, error) {
-                            f.log('failed loading: ' + url);
-                            loadComplete('failed loading resource.json error: ' + error);
-                        },
-                        dataType: "json",
-                        async : options.getAsync
-                    });
-                }    
-            }
-        },
-    
-        _fetchOne: function(lng, ns, options, done) {
-            var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
-            f.ajax({
-                url: url,
-                success: function(data, status, xhr) {
-                    f.log('loaded: ' + url);
-                    done(null, data);
-                },
-                error : function(xhr, status, error) {
-                    if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
-                        // file loaded but invalid json, stop waste time !
-                        f.error('There is a typo in: ' + url);
-                    } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
-                        f.log('Does not exist: ' + url);
-                    } else {
-                        var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
-                        f.log(theStatus + ' when loading ' + url);
-                    }
-                    
-                    done(error, {});
-                },
-                dataType: "json",
-                async : options.getAsync
-            });
-        },
-    
-        postMissing: function(lng, ns, key, defaultValue, lngs) {
-            var payload = {};
-            payload[key] = defaultValue;
-    
-            var urls = [];
-    
-            if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
-                for (var i = 0; i < o.fallbackLng.length; i++) {
-                    urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
-                }
-            } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
-                urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
-            } else if (o.sendMissingTo === 'all') {
-                for (var i = 0, l = lngs.length; i < l; i++) {
-                    urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
-                }
-            }
-    
-            for (var y = 0, len = urls.length; y < len; y++) {
-                var item = urls[y];
-                f.ajax({
-                    url: item.url,
-                    type: o.sendType,
-                    data: payload,
-                    success: function(data, status, xhr) {
-                        f.log('posted missing key \'' + key + '\' to: ' + item.url);
-    
-                        // add key to resStore
-                        var keys = key.split('.');
-                        var x = 0;
-                        var value = resStore[item.lng][ns];
-                        while (keys[x]) {
-                            if (x === keys.length - 1) {
-                                value = value[keys[x]] = defaultValue;
-                            } else {
-                                value = value[keys[x]] = value[keys[x]] || {};
-                            }
-                            x++;
-                        }
-                    },
-                    error : function(xhr, status, error) {
-                        f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
-                    },
-                    dataType: "json",
-                    async : o.postAsync
-                });
-            }
-        }
-    };
-    // defaults
-    var o = {
-        lng: undefined,
-        load: 'all',
-        preload: [],
-        lowerCaseLng: false,
-        returnObjectTrees: false,
-        fallbackLng: ['dev'],
-        fallbackNS: [],
-        detectLngQS: 'setLng',
-        detectLngFromLocalStorage: false,
-        ns: 'translation',
-        fallbackOnNull: true,
-        fallbackOnEmpty: false,
-        fallbackToDefaultNS: false,
-        nsseparator: ':',
-        keyseparator: '.',
-        selectorAttr: 'data-i18n',
-        debug: false,
-        
-        resGetPath: 'locales/__lng__/__ns__.json',
-        resPostPath: 'locales/add/__lng__/__ns__',
-    
-        getAsync: true,
-        postAsync: true,
-    
-        resStore: undefined,
-        useLocalStorage: false,
-        localStorageExpirationTime: 7*24*60*60*1000,
-    
-        dynamicLoad: false,
-        sendMissing: false,
-        sendMissingTo: 'fallback', // current | all
-        sendType: 'POST',
-    
-        interpolationPrefix: '__',
-        interpolationSuffix: '__',
-        reusePrefix: '$t(',
-        reuseSuffix: ')',
-        pluralSuffix: '_plural',
-        pluralNotFound: ['plural_not_found', Math.random()].join(''),
-        contextNotFound: ['context_not_found', Math.random()].join(''),
-        escapeInterpolation: false,
-        indefiniteSuffix: '_indefinite',
-        indefiniteNotFound: ['indefinite_not_found', Math.random()].join(''),
-    
-        setJqueryExt: true,
-        defaultValueFromContent: true,
-        useDataAttrOptions: false,
-        cookieExpirationTime: undefined,
-        useCookie: true,
-        cookieName: 'i18next',
-        cookieDomain: undefined,
-    
-        objectTreeKeyHandler: undefined,
-        postProcess: undefined,
-        parseMissingKey: undefined,
-        missingKeyHandler: sync.postMissing,
-    
-        shortcutFunction: 'sprintf' // or: defaultValue
-    };
-    function _extend(target, source) {
-        if (!source || typeof source === 'function') {
-            return target;
-        }
-    
-        for (var attr in source) { target[attr] = source[attr]; }
-        return target;
-    }
-    
-    function _deepExtend(target, source) {
-        for (var prop in source)
-            if (prop in target)
-                _deepExtend(target[prop], source[prop]);
-            else
-                target[prop] = source[prop];
-        return target;
-    }
-    
-    function _each(object, callback, args) {
-        var name, i = 0,
-            length = object.length,
-            isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
-    
-        if (args) {
-            if (isObj) {
-                for (name in object) {
-                    if (callback.apply(object[name], args) === false) {
-                        break;
-                    }
-                }
-            } else {
-                for ( ; i < length; ) {
-                    if (callback.apply(object[i++], args) === false) {
-                        break;
-                    }
-                }
-            }
-    
-        // A special, fast, case for the most common use of each
-        } else {
-            if (isObj) {
-                for (name in object) {
-                    if (callback.call(object[name], name, object[name]) === false) {
-                        break;
-                    }
-                }
-            } else {
-                for ( ; i < length; ) {
-                    if (callback.call(object[i], i, object[i++]) === false) {
-                        break;
-                    }
-                }
-            }
-        }
-    
-        return object;
-    }
-    
-    var _entityMap = {
-        "&": "&amp;",
-        "<": "&lt;",
-        ">": "&gt;",
-        '"': '&quot;',
-        "'": '&#39;',
-        "/": '&#x2F;'
-    };
-    
-    function _escape(data) {
-        if (typeof data === 'string') {
-            return data.replace(/[&<>"'\/]/g, function (s) {
-                return _entityMap[s];
-            });
-        }else{
-            return data;
-        }
-    }
-    
-    function _ajax(options) {
-    
-        // v0.5.0 of https://github.com/goloroden/http.js
-        var getXhr = function (callback) {
-            // Use the native XHR object if the browser supports it.
-            if (window.XMLHttpRequest) {
-                return callback(null, new XMLHttpRequest());
-            } else if (window.ActiveXObject) {
-                // In Internet Explorer check for ActiveX versions of the XHR object.
-                try {
-                    return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
-                } catch (e) {
-                    return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
-                }
-            }
-    
-            // If no XHR support was found, throw an error.
-            return callback(new Error());
-        };
-    
-        var encodeUsingUrlEncoding = function (data) {
-            if(typeof data === 'string') {
-                return data;
-            }
-    
-            var result = [];
-            for(var dataItem in data) {
-                if(data.hasOwnProperty(dataItem)) {
-                    result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
-                }
-            }
-    
-            return result.join('&');
-        };
-    
-        var utf8 = function (text) {
-            text = text.replace(/\r\n/g, '\n');
-            var result = '';
-    
-            for(var i = 0; i < text.length; i++) {
-                var c = text.charCodeAt(i);
-    
-                if(c < 128) {
-                        result += String.fromCharCode(c);
-                } else if((c > 127) && (c < 2048)) {
-                        result += String.fromCharCode((c >> 6) | 192);
-                        result += String.fromCharCode((c & 63) | 128);
-                } else {
-                        result += String.fromCharCode((c >> 12) | 224);
-                        result += String.fromCharCode(((c >> 6) & 63) | 128);
-                        result += String.fromCharCode((c & 63) | 128);
-                }
-            }
-    
-            return result;
-        };
-    
-        var base64 = function (text) {
-            var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
-    
-            text = utf8(text);
-            var result = '',
-                    chr1, chr2, chr3,
-                    enc1, enc2, enc3, enc4,
-                    i = 0;
-    
-            do {
-                chr1 = text.charCodeAt(i++);
-                chr2 = text.charCodeAt(i++);
-                chr3 = text.charCodeAt(i++);
-    
-                enc1 = chr1 >> 2;
-                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
-                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
-                enc4 = chr3 & 63;
-    
-                if(isNaN(chr2)) {
-                    enc3 = enc4 = 64;
-                } else if(isNaN(chr3)) {
-                    enc4 = 64;
-                }
-    
-                result +=
-                    keyStr.charAt(enc1) +
-                    keyStr.charAt(enc2) +
-                    keyStr.charAt(enc3) +
-                    keyStr.charAt(enc4);
-                chr1 = chr2 = chr3 = '';
-                enc1 = enc2 = enc3 = enc4 = '';
-            } while(i < text.length);
-    
-            return result;
-        };
-    
-        var mergeHeaders = function () {
-            // Use the first header object as base.
-            var result = arguments[0];
-    
-            // Iterate through the remaining header objects and add them.
-            for(var i = 1; i < arguments.length; i++) {
-                var currentHeaders = arguments[i];
-                for(var header in currentHeaders) {
-                    if(currentHeaders.hasOwnProperty(header)) {
-                        result[header] = currentHeaders[header];
-                    }
-                }
-            }
-    
-            // Return the merged headers.
-            return result;
-        };
-    
-        var ajax = function (method, url, options, callback) {
-            // Adjust parameters.
-            if(typeof options === 'function') {
-                callback = options;
-                options = {};
-            }
-    
-            // Set default parameter values.
-            options.cache = options.cache || false;
-            options.data = options.data || {};
-            options.headers = options.headers || {};
-            options.jsonp = options.jsonp || false;
-            options.async = options.async === undefined ? true : options.async;
-    
-            // Merge the various header objects.
-            var headers = mergeHeaders({
-                'accept': '*/*',
-                'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
-            }, ajax.headers, options.headers);
-    
-            // Encode the data according to the content-type.
-            var payload;
-            if (headers['content-type'] === 'application/json') {
-                payload = JSON.stringify(options.data);
-            } else {
-                payload = encodeUsingUrlEncoding(options.data);
-            }
-    
-            // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
-            // if neccessary.
-            if(method === 'GET') {
-                // Setup the query string.
-                var queryString = [];
-                if(payload) {
-                    queryString.push(payload);
-                    payload = null;
-                }
-    
-                // Handle caching.
-                if(!options.cache) {
-                    queryString.push('_=' + (new Date()).getTime());
-                }
-    
-                // If neccessary prepare the query string for a JSONP call.
-                if(options.jsonp) {
-                    queryString.push('callback=' + options.jsonp);
-                    queryString.push('jsonp=' + options.jsonp);
-                }
-    
-                // Merge the query string and attach it to the url.
-                queryString = queryString.join('&');
-                if (queryString.length > 1) {
-                    if (url.indexOf('?') > -1) {
-                        url += '&' + queryString;
-                    } else {
-                        url += '?' + queryString;
-                    }
-                }
-    
-                // Make a JSONP call if neccessary.
-                if(options.jsonp) {
-                    var head = document.getElementsByTagName('head')[0];
-                    var script = document.createElement('script');
-                    script.type = 'text/javascript';
-                    script.src = url;
-                    head.appendChild(script);
-                    return;
-                }
-            }
-    
-            // Since we got here, it is no JSONP request, so make a normal XHR request.
-            getXhr(function (err, xhr) {
-                if(err) return callback(err);
-    
-                // Open the request.
-                xhr.open(method, url, options.async);
-    
-                // Set the request headers.
-                for(var header in headers) {
-                    if(headers.hasOwnProperty(header)) {
-                        xhr.setRequestHeader(header, headers[header]);
-                    }
-                }
-    
-                // Handle the request events.
-                xhr.onreadystatechange = function () {
-                    if(xhr.readyState === 4) {
-                        var data = xhr.responseText || '';
-    
-                        // If no callback is given, return.
-                        if(!callback) {
-                            return;
-                        }
-    
-                        // Return an object that provides access to the data as text and JSON.
-                        callback(xhr.status, {
-                            text: function () {
-                                return data;
-                            },
-    
-                            json: function () {
-                                return JSON.parse(data);
-                            }
-                        });
-                    }
-                };
-    
-                // Actually send the XHR request.
-                xhr.send(payload);
-            });
-        };
-    
-        // Define the external interface.
-        var http = {
-            authBasic: function (username, password) {
-                ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
-            },
-    
-            connect: function (url, options, callback) {
-                return ajax('CONNECT', url, options, callback);
-            },
-    
-            del: function (url, options, callback) {
-                return ajax('DELETE', url, options, callback);
-            },
-    
-            get: function (url, options, callback) {
-                return ajax('GET', url, options, callback);
-            },
-    
-            head: function (url, options, callback) {
-                return ajax('HEAD', url, options, callback);
-            },
-    
-            headers: function (headers) {
-                ajax.headers = headers || {};
-            },
-    
-            isAllowed: function (url, verb, callback) {
-                this.options(url, function (status, data) {
-                    callback(data.text().indexOf(verb) !== -1);
-                });
-            },
-    
-            options: function (url, options, callback) {
-                return ajax('OPTIONS', url, options, callback);
-            },
-    
-            patch: function (url, options, callback) {
-                return ajax('PATCH', url, options, callback);
-            },
-    
-            post: function (url, options, callback) {
-                return ajax('POST', url, options, callback);
-            },
-    
-            put: function (url, options, callback) {
-                return ajax('PUT', url, options, callback);
-            },
-    
-            trace: function (url, options, callback) {
-                return ajax('TRACE', url, options, callback);
-            }
-        };
-    
-    
-        var methode = options.type ? options.type.toLowerCase() : 'get';
-    
-        http[methode](options.url, options, function (status, data) {
-            // file: protocol always gives status code 0, so check for data
-            if (status === 200 || (status === 0 && data.text())) {
-                options.success(data.json(), status, null);
-            } else {
-                options.error(data.text(), status, null);
-            }
-        });
-    }
-    
-    var _cookie = {
-        create: function(name,value,minutes,domain) {
-            var expires;
-            if (minutes) {
-                var date = new Date();
-                date.setTime(date.getTime()+(minutes*60*1000));
-                expires = "; expires="+date.toGMTString();
-            }
-            else expires = "";
-            domain = (domain)? "domain="+domain+";" : "";
-            document.cookie = name+"="+value+expires+";"+domain+"path=/";
-        },
-    
-        read: function(name) {
-            var nameEQ = name + "=";
-            var ca = document.cookie.split(';');
-            for(var i=0;i < ca.length;i++) {
-                var c = ca[i];
-                while (c.charAt(0)==' ') c = c.substring(1,c.length);
-                if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
-            }
-            return null;
-        },
-    
-        remove: function(name) {
-            this.create(name,"",-1);
-        }
-    };
-    
-    var cookie_noop = {
-        create: function(name,value,minutes,domain) {},
-        read: function(name) { return null; },
-        remove: function(name) {}
-    };
-    
-    
-    
-    // move dependent functions to a container so that
-    // they can be overriden easier in no jquery environment (node.js)
-    var f = {
-        extend: $ ? $.extend : _extend,
-        deepExtend: _deepExtend,
-        each: $ ? $.each : _each,
-        ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
-        cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
-        detectLanguage: detectLanguage,
-        escape: _escape,
-        log: function(str) {
-            if (o.debug && typeof console !== "undefined") console.log(str);
-        },
-        error: function(str) {
-            if (typeof console !== "undefined") console.error(str);
-        },
-        getCountyIndexOfLng: function(lng) {
-            var lng_index = 0;
-            if (lng === 'nb-NO' || lng === 'nn-NO') lng_index = 1;
-            return lng_index;
-        },
-        toLanguages: function(lng) {
-            var log = this.log;
-    
-            var languages = [];
-            var whitelist = o.lngWhitelist || false;
-            var addLanguage = function(language){
-              //reject langs not whitelisted
-              if(!whitelist || whitelist.indexOf(language) > -1){
-                languages.push(language);
-              }else{
-                log('rejecting non-whitelisted language: ' + language);
-              }
-            };
-            if (typeof lng === 'string' && lng.indexOf('-') > -1) {
-                var parts = lng.split('-');
-    
-                lng = o.lowerCaseLng ?
-                    parts[0].toLowerCase() +  '-' + parts[1].toLowerCase() :
-                    parts[0].toLowerCase() +  '-' + parts[1].toUpperCase();
-    
-                if (o.load !== 'unspecific') addLanguage(lng);
-                if (o.load !== 'current') addLanguage(parts[this.getCountyIndexOfLng(lng)]);
-            } else {
-                addLanguage(lng);
-            }
-    
-            for (var i = 0; i < o.fallbackLng.length; i++) {
-                if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(o.fallbackLng[i]);
-            }
-            return languages;
-        },
-        regexEscape: function(str) {
-            return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-        },
-        regexReplacementEscape: function(strOrFn) {
-            if (typeof strOrFn === 'string') {
-                return strOrFn.replace(/\$/g, "$$$$");
-            } else {
-                return strOrFn;
-            }
-        }
-    };
-    function init(options, cb) {
-        
-        if (typeof options === 'function') {
-            cb = options;
-            options = {};
-        }
-        options = options || {};
-        
-        // override defaults with passed in options
-        f.extend(o, options);
-        delete o.fixLng; /* passed in each time */
-    
-        // create namespace object if namespace is passed in as string
-        if (typeof o.ns == 'string') {
-            o.ns = { namespaces: [o.ns], defaultNs: o.ns};
-        }
-    
-        // fallback namespaces
-        if (typeof o.fallbackNS == 'string') {
-            o.fallbackNS = [o.fallbackNS];
-        }
-    
-        // fallback languages
-        if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
-            o.fallbackLng = [o.fallbackLng];
-        }
-    
-        // escape prefix/suffix
-        o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
-        o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
-    
-        if (!o.lng) o.lng = f.detectLanguage();
-    
-        languages = f.toLanguages(o.lng);
-        currentLng = languages[0];
-        f.log('currentLng set to: ' + currentLng);
-    
-        if (o.useCookie && f.cookie.read(o.cookieName) !== currentLng){ //cookie is unset or invalid
-            f.cookie.create(o.cookieName, currentLng, o.cookieExpirationTime, o.cookieDomain);
-        }
-        if (o.detectLngFromLocalStorage && typeof document !== 'undefined' && window.localstorage) {
-            window.localStorage.setItem('i18next_lng', currentLng);
-        }
-    
-        var lngTranslate = translate;
-        if (options.fixLng) {
-            lngTranslate = function(key, options) {
-                options = options || {};
-                options.lng = options.lng || lngTranslate.lng;
-                return translate(key, options);
-            };
-            lngTranslate.lng = currentLng;
-        }
-    
-        pluralExtensions.setCurrentLng(currentLng);
-    
-        // add JQuery extensions
-        if ($ && o.setJqueryExt) addJqueryFunct();
-    
-        // jQuery deferred
-        var deferred;
-        if ($ && $.Deferred) {
-            deferred = $.Deferred();
-        }
-    
-        // return immidiatly if res are passed in
-        if (o.resStore) {
-            resStore = o.resStore;
-            initialized = true;
-            if (cb) cb(lngTranslate);
-            if (deferred) deferred.resolve(lngTranslate);
-            if (deferred) return deferred.promise();
-            return;
-        }
-    
-        // languages to load
-        var lngsToLoad = f.toLanguages(o.lng);
-        if (typeof o.preload === 'string') o.preload = [o.preload];
-        for (var i = 0, l = o.preload.length; i < l; i++) {
-            var pres = f.toLanguages(o.preload[i]);
-            for (var y = 0, len = pres.length; y < len; y++) {
-                if (lngsToLoad.indexOf(pres[y]) < 0) {
-                    lngsToLoad.push(pres[y]);
-                }
-            }
-        }
-    
-        // else load them
-        i18n.sync.load(lngsToLoad, o, function(err, store) {
-            resStore = store;
-            initialized = true;
-    
-            if (cb) cb(lngTranslate);
-            if (deferred) deferred.resolve(lngTranslate);
-        });
-    
-        if (deferred) return deferred.promise();
-    }
-    function preload(lngs, cb) {
-        if (typeof lngs === 'string') lngs = [lngs];
-        for (var i = 0, l = lngs.length; i < l; i++) {
-            if (o.preload.indexOf(lngs[i]) < 0) {
-                o.preload.push(lngs[i]);
-            }
-        }
-        return init(cb);
-    }
-    
-    function addResourceBundle(lng, ns, resources, deep) {
-        if (typeof ns !== 'string') {
-            resources = ns;
-            ns = o.ns.defaultNs;
-        } else if (o.ns.namespaces.indexOf(ns) < 0) {
-            o.ns.namespaces.push(ns);
-        }
-    
-        resStore[lng] = resStore[lng] || {};
-        resStore[lng][ns] = resStore[lng][ns] || {};
-    
-        if (deep) {
-            f.deepExtend(resStore[lng][ns], resources);
-        } else {
-            f.extend(resStore[lng][ns], resources);
-        }
-    }
-    
-    function removeResourceBundle(lng, ns) {
-        if (typeof ns !== 'string') {
-            ns = o.ns.defaultNs;
-        }
-    
-        resStore[lng] = resStore[lng] || {};
-        resStore[lng][ns] = {};
-    }
-    
-    function addResource(lng, ns, key, value) {
-        if (typeof ns !== 'string') {
-            resource = ns;
-            ns = o.ns.defaultNs;
-        } else if (o.ns.namespaces.indexOf(ns) < 0) {
-            o.ns.namespaces.push(ns);
-        }
-    
-        resStore[lng] = resStore[lng] || {};
-        resStore[lng][ns] = resStore[lng][ns] || {};
-    
-        var keys = key.split(o.keyseparator);
-        var x = 0;
-        var node = resStore[o.lng][ns];
-        var origRef = node;
-    
-        while (keys[x]) {
-            if (x == keys.length - 1)
-                node[keys[x]] = value;
-            else {
-                if (node[keys[x]] == null)
-                    node[keys[x]] = {};
-    
-                node = node[keys[x]];
-            }
-            x++;
-        }
-    }
-    
-    function addResources(lng, ns, resources) {
-        if (typeof ns !== 'string') {
-            resource = ns;
-            ns = o.ns.defaultNs;
-        } else if (o.ns.namespaces.indexOf(ns) < 0) {
-            o.ns.namespaces.push(ns);
-        }
-    
-        for (var m in resources) {
-            if (typeof resources[m] === 'string') addResource(lng, ns, m, resources[m]);
-        }
-    }
-    
-    function setDefaultNamespace(ns) {
-        o.ns.defaultNs = ns;
-    }
-    
-    function loadNamespace(namespace, cb) {
-        loadNamespaces([namespace], cb);
-    }
-    
-    function loadNamespaces(namespaces, cb) {
-        var opts = {
-            dynamicLoad: o.dynamicLoad,
-            resGetPath: o.resGetPath,
-            getAsync: o.getAsync,
-            customLoad: o.customLoad,
-            ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
-        };
-    
-        // languages to load
-        var lngsToLoad = f.toLanguages(o.lng);
-        if (typeof o.preload === 'string') o.preload = [o.preload];
-        for (var i = 0, l = o.preload.length; i < l; i++) {
-            var pres = f.toLanguages(o.preload[i]);
-            for (var y = 0, len = pres.length; y < len; y++) {
-                if (lngsToLoad.indexOf(pres[y]) < 0) {
-                    lngsToLoad.push(pres[y]);
-                }
-            }
-        }
-    
-        // check if we have to load
-        var lngNeedLoad = [];
-        for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
-            var needLoad = false;
-            var resSet = resStore[lngsToLoad[a]];
-            if (resSet) {
-                for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
-                    if (!resSet[namespaces[b]]) needLoad = true;
-                }
-            } else {
-                needLoad = true;
-            }
-    
-            if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
-        }
-    
-        if (lngNeedLoad.length) {
-            i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
-                var todo = namespaces.length * lngNeedLoad.length;
-    
-                // load each file individual
-                f.each(namespaces, function(nsIndex, nsValue) {
-    
-                    // append namespace to namespace array
-                    if (o.ns.namespaces.indexOf(nsValue) < 0) {
-                        o.ns.namespaces.push(nsValue);
-                    }
-    
-                    f.each(lngNeedLoad, function(lngIndex, lngValue) {
-                        resStore[lngValue] = resStore[lngValue] || {};
-                        resStore[lngValue][nsValue] = store[lngValue][nsValue];
-    
-                        todo--; // wait for all done befor callback
-                        if (todo === 0 && cb) {
-                            if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
-                            cb();
-                        }
-                    });
-                });
-            });
-        } else {
-            if (cb) cb();
-        }
-    }
-    
-    function setLng(lng, options, cb) {
-        if (typeof options === 'function') {
-            cb = options;
-            options = {};
-        } else if (!options) {
-            options = {};
-        }
-    
-        options.lng = lng;
-        return init(options, cb);
-    }
-    
-    function lng() {
-        return currentLng;
-    }
-    function addJqueryFunct() {
-        // $.t shortcut
-        $.t = $.t || translate;
-    
-        function parse(ele, key, options) {
-            if (key.length === 0) return;
-    
-            var attr = 'text';
-    
-            if (key.indexOf('[') === 0) {
-                var parts = key.split(']');
-                key = parts[1];
-                attr = parts[0].substr(1, parts[0].length-1);
-            }
-    
-            if (key.indexOf(';') === key.length-1) {
-                key = key.substr(0, key.length-2);
-            }
-    
-            var optionsToUse;
-            if (attr === 'html') {
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
-                ele.html($.t(key, optionsToUse));
-            } else if (attr === 'text') {
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
-                ele.text($.t(key, optionsToUse));
-            } else if (attr === 'prepend') {
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
-                ele.prepend($.t(key, optionsToUse));
-            } else if (attr === 'append') {
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
-                ele.append($.t(key, optionsToUse));
-            } else if (attr.indexOf("data-") === 0) {
-                var dataAttr = attr.substr(("data-").length);
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
-                var translated = $.t(key, optionsToUse);
-                //we change into the data cache
-                ele.data(dataAttr, translated);
-                //we change into the dom
-                ele.attr(attr, translated);
-            } else {
-                optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
-                ele.attr(attr, $.t(key, optionsToUse));
-            }
-        }
-    
-        function localize(ele, options) {
-            var key = ele.attr(o.selectorAttr);
-            if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
-            if (!key) return;
-    
-            var target = ele
-              , targetSelector = ele.data("i18n-target");
-            if (targetSelector) {
-                target = ele.find(targetSelector) || ele;
-            }
-    
-            if (!options && o.useDataAttrOptions === true) {
-                options = ele.data("i18n-options");
-            }
-            options = options || {};
-    
-            if (key.indexOf(';') >= 0) {
-                var keys = key.split(';');
-    
-                $.each(keys, function(m, k) {
-                    if (k !== '') parse(target, k, options);
-                });
-    
-            } else {
-                parse(target, key, options);
-            }
-    
-            if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
-        }
-    
-        // fn
-        $.fn.i18n = function (options) {
-            return this.each(function() {
-                // localize element itself
-                localize($(this), options);
-    
-                // localize childs
-                var elements =  $(this).find('[' + o.selectorAttr + ']');
-                elements.each(function() { 
-                    localize($(this), options);
-                });
-            });
-        };
-    }
-    function applyReplacement(str, replacementHash, nestedKey, options) {
-        if (!str) return str;
-    
-        options = options || replacementHash; // first call uses replacement hash combined with options
-        if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
-    
-        var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
-          , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
-          , unEscapingSuffix = 'HTML'+suffix;
-    
-        var hash = replacementHash.replace && typeof replacementHash.replace === 'object' ? replacementHash.replace : replacementHash;
-        f.each(hash, function(key, value) {
-            var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
-            if (typeof value === 'object' && value !== null) {
-                str = applyReplacement(str, value, nextKey, options);
-            } else {
-                if (options.escapeInterpolation || o.escapeInterpolation) {
-                    str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), f.regexReplacementEscape(value));
-                    str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(f.escape(value)));
-                } else {
-                    str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(value));
-                }
-                // str = options.escapeInterpolation;
-            }
-        });
-        return str;
-    }
-    
-    // append it to functions
-    f.applyReplacement = applyReplacement;
-    
-    function applyReuse(translated, options) {
-        var comma = ',';
-        var options_open = '{';
-        var options_close = '}';
-    
-        var opts = f.extend({}, options);
-        delete opts.postProcess;
-    
-        while (translated.indexOf(o.reusePrefix) != -1) {
-            replacementCounter++;
-            if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
-            var index_of_opening = translated.lastIndexOf(o.reusePrefix);
-            var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
-            var token = translated.substring(index_of_opening, index_of_end_of_closing);
-            var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
-    
-            if (index_of_end_of_closing <= index_of_opening) {
-                f.error('there is an missing closing in following translation value', translated);
-                return '';
-            }
-    
-            if (token_without_symbols.indexOf(comma) != -1) {
-                var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
-                if (token_without_symbols.indexOf(options_open, index_of_token_end_of_closing) != -1 && token_without_symbols.indexOf(options_close, index_of_token_end_of_closing) != -1) {
-                    var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
-                    var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
-                    try {
-                        opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
-                        token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
-                    } catch (e) {
-                    }
-                }
-            }
-    
-            var translated_token = _translate(token_without_symbols, opts);
-            translated = translated.replace(token, f.regexReplacementEscape(translated_token));
-        }
-        return translated;
-    }
-    
-    function hasContext(options) {
-        return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
-    }
-    
-    function needsPlural(options, lng) {
-        return (options.count !== undefined && typeof options.count != 'string' && pluralExtensions.needsPlural(lng, options.count));
-    }
-    
-    function needsIndefiniteArticle(options) {
-        return (options.indefinite_article !== undefined && typeof options.indefinite_article != 'string' && options.indefinite_article);
-    }
-    
-    function exists(key, options) {
-        options = options || {};
-    
-        var notFound = _getDefaultValue(key, options)
-            , found = _find(key, options);
-    
-        return found !== undefined || found === notFound;
-    }
-    
-    function translate(key, options) {
-        options = options || {};
-    
-        if (!initialized) {
-            f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
-            return options.defaultValue || '';
-        };
-        replacementCounter = 0;
-        return _translate.apply(null, arguments);
-    }
-    
-    function _getDefaultValue(key, options) {
-        return (options.defaultValue !== undefined) ? options.defaultValue : key;
-    }
-    
-    function _injectSprintfProcessor() {
-    
-        var values = [];
-    
-        // mh: build array from second argument onwards
-        for (var i = 1; i < arguments.length; i++) {
-            values.push(arguments[i]);
-        }
-    
-        return {
-            postProcess: 'sprintf',
-            sprintf:     values
-        };
-    }
-    
-    function _translate(potentialKeys, options) {
-        if (options && typeof options !== 'object') {
-            if (o.shortcutFunction === 'sprintf') {
-                // mh: gettext like sprintf syntax found, automatically create sprintf processor
-                options = _injectSprintfProcessor.apply(null, arguments);
-            } else if (o.shortcutFunction === 'defaultValue') {
-                options = {
-                    defaultValue: options
-                }
-            }
-        } else {
-            options = options || {};
-        }
-    
-        if (potentialKeys === undefined || potentialKeys === null || potentialKeys === '') return '';
-    
-        if (typeof potentialKeys == 'string') {
-            potentialKeys = [potentialKeys];
-        }
-    
-        var key = potentialKeys[0];
-    
-        if (potentialKeys.length > 1) {
-            for (var i = 0; i < potentialKeys.length; i++) {
-                key = potentialKeys[i];
-                if (exists(key, options)) {
-                    break;
-                }
-            }
-        }
-    
-        var notFound = _getDefaultValue(key, options)
-            , found = _find(key, options)
-            , lngs = options.lng ? f.toLanguages(options.lng, options.fallbackLng) : languages
-            , ns = options.ns || o.ns.defaultNs
-            , parts;
-    
-        // split ns and key
-        if (key.indexOf(o.nsseparator) > -1) {
-            parts = key.split(o.nsseparator);
-            ns = parts[0];
-            key = parts[1];
-        }
-    
-        if (found === undefined && o.sendMissing && typeof o.missingKeyHandler === 'function') {
-            if (options.lng) {
-                o.missingKeyHandler(lngs[0], ns, key, notFound, lngs);
-            } else {
-                o.missingKeyHandler(o.lng, ns, key, notFound, lngs);
-            }
-        }
-    
-        var postProcessor = options.postProcess || o.postProcess;
-        if (found !== undefined && postProcessor) {
-            if (postProcessors[postProcessor]) {
-                found = postProcessors[postProcessor](found, key, options);
-            }
-        }
-    
-        // process notFound if function exists
-        var splitNotFound = notFound;
-        if (notFound.indexOf(o.nsseparator) > -1) {
-            parts = notFound.split(o.nsseparator);
-            splitNotFound = parts[1];
-        }
-        if (splitNotFound === key && o.parseMissingKey) {
-            notFound = o.parseMissingKey(notFound);
-        }
-    
-        if (found === undefined) {
-            notFound = applyReplacement(notFound, options);
-            notFound = applyReuse(notFound, options);
-    
-            if (postProcessor && postProcessors[postProcessor]) {
-                var val = _getDefaultValue(key, options);
-                found = postProcessors[postProcessor](val, key, options);
-            }
-        }
-    
-        return (found !== undefined) ? found : notFound;
-    }
-    
-    function _find(key, options) {
-        options = options || {};
-    
-        var optionWithoutCount, translated
-            , notFound = _getDefaultValue(key, options)
-            , lngs = languages;
-    
-        if (!resStore) { return notFound; } // no resStore to translate from
-    
-        // CI mode
-        if (lngs[0].toLowerCase() === 'cimode') return notFound;
-    
-        // passed in lng
-        if (options.lng) {
-            lngs = f.toLanguages(options.lng, options.fallbackLng);
-    
-            if (!resStore[lngs[0]]) {
-                var oldAsync = o.getAsync;
-                o.getAsync = false;
-    
-                i18n.sync.load(lngs, o, function(err, store) {
-                    f.extend(resStore, store);
-                    o.getAsync = oldAsync;
-                });
-            }
-        }
-    
-        var ns = options.ns || o.ns.defaultNs;
-        if (key.indexOf(o.nsseparator) > -1) {
-            var parts = key.split(o.nsseparator);
-            ns = parts[0];
-            key = parts[1];
-        }
-    
-        if (hasContext(options)) {
-            optionWithoutCount = f.extend({}, options);
-            delete optionWithoutCount.context;
-            optionWithoutCount.defaultValue = o.contextNotFound;
-    
-            var contextKey = ns + o.nsseparator + key + '_' + options.context;
-    
-            translated = translate(contextKey, optionWithoutCount);
-            if (translated != o.contextNotFound) {
-                return applyReplacement(translated, { context: options.context }); // apply replacement for context only
-            } // else continue translation with original/nonContext key
-        }
-    
-        if (needsPlural(options, lngs[0])) {
-            optionWithoutCount = f.extend({}, options);
-            delete optionWithoutCount.count;
-            optionWithoutCount.defaultValue = o.pluralNotFound;
-    
-            var pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
-            var pluralExtension = pluralExtensions.get(lngs[0], options.count);
-            if (pluralExtension >= 0) {
-                pluralKey = pluralKey + '_' + pluralExtension;
-            } else if (pluralExtension === 1) {
-                pluralKey = ns + o.nsseparator + key; // singular
-            }
-    
-            translated = translate(pluralKey, optionWithoutCount);
-            if (translated != o.pluralNotFound) {
-                return applyReplacement(translated, {
-                    count: options.count,
-                    interpolationPrefix: options.interpolationPrefix,
-                    interpolationSuffix: options.interpolationSuffix
-                }); // apply replacement for count only
-            } // else continue translation with original/singular key
-        }
-    
-        if (needsIndefiniteArticle(options)) {
-            var optionsWithoutIndef = f.extend({}, options);
-            delete optionsWithoutIndef.indefinite_article;
-            optionsWithoutIndef.defaultValue = o.indefiniteNotFound;
-            // If we don't have a count, we want the indefinite, if we do have a count, and needsPlural is false
-            var indefiniteKey = ns + o.nsseparator + key + (((options.count && !needsPlural(options, lngs[0])) || !options.count) ? o.indefiniteSuffix : "");
-            translated = translate(indefiniteKey, optionsWithoutIndef);
-            if (translated != o.indefiniteNotFound) {
-                return translated;
-            }
-        }
-    
-        var found;
-        var keys = key.split(o.keyseparator);
-        for (var i = 0, len = lngs.length; i < len; i++ ) {
-            if (found !== undefined) break;
-    
-            var l = lngs[i];
-    
-            var x = 0;
-            var value = resStore[l] && resStore[l][ns];
-            while (keys[x]) {
-                value = value && value[keys[x]];
-                x++;
-            }
-            if (value !== undefined) {
-                var valueType = Object.prototype.toString.apply(value);
-                if (typeof value === 'string') {
-                    value = applyReplacement(value, options);
-                    value = applyReuse(value, options);
-                } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
-                    value = value.join('\n');
-                    value = applyReplacement(value, options);
-                    value = applyReuse(value, options);
-                } else if (value === null && o.fallbackOnNull === true) {
-                    value = undefined;
-                } else if (value !== null) {
-                    if (!o.returnObjectTrees && !options.returnObjectTrees) {
-                        if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
-                            value = o.objectTreeKeyHandler(key, value, l, ns, options);
-                        } else {
-                            value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
-                                'returned an object instead of string.';
-                            f.log(value);
-                        }
-                    } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
-                        var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
-                        f.each(value, function(m) {
-                            copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
-                        });
-                        value = copy;
-                    }
-                }
-    
-                if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
-                    value = undefined;
-    
-                found = value;
-            }
-        }
-    
-        if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
-            // set flag for fallback lookup - avoid recursion
-            options.isFallbackLookup = true;
-    
-            if (o.fallbackNS.length) {
-    
-                for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
-                    found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
-    
-                    if (found) {
-                        /* compare value without namespace */
-                        var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
-                          , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
-    
-                        if (foundValue !== notFoundValue) break;
-                    }
-                }
-            } else {
-                found = _find(key, options); // fallback to default NS
-            }
-            options.isFallbackLookup = false;
-        }
-    
-        return found;
-    }
-    function detectLanguage() {
-        var detectedLng;
-    
-        // get from qs
-        var qsParm = [];
-        if (typeof window !== 'undefined') {
-            (function() {
-                var query = window.location.search.substring(1);
-                var parms = query.split('&');
-                for (var i=0; i<parms.length; i++) {
-                    var pos = parms[i].indexOf('=');
-                    if (pos > 0) {
-                        var key = parms[i].substring(0,pos);
-                        var val = parms[i].substring(pos+1);
-                        qsParm[key] = val;
-                    }
-                }
-            })();
-            if (qsParm[o.detectLngQS]) {
-                detectedLng = qsParm[o.detectLngQS];
-            }
-        }
-    
-        // get from cookie
-        if (!detectedLng && typeof document !== 'undefined' && o.useCookie ) {
-            var c = f.cookie.read(o.cookieName);
-            if (c) detectedLng = c;
-        }
-    
-        // get from localstorage
-        if (!detectedLng && typeof document !== 'undefined' && window.localstorage && o.detectLngFromLocalStorage) {
-            detectedLng = window.localStorage.getItem('i18next_lng');
-        }
-    
-        // get from navigator
-        if (!detectedLng && typeof navigator !== 'undefined') {
-            detectedLng = (navigator.language) ? navigator.language : navigator.userLanguage;
-        }
-    
-        //fallback
-        if(!detectedLng){
-          detectedLng = o.fallbackLng[0];
-        }
-        
-        return detectedLng;
-    }
-    // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
-    var pluralExtensions = {
-    
-        rules: {
-            "ach": {
-                "name": "Acholi", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "af": {
-                "name": "Afrikaans", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ak": {
-                "name": "Akan", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "am": {
-                "name": "Amharic", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "an": {
-                "name": "Aragonese", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ar": {
-                "name": "Arabic", 
-                "numbers": [
-                    0, 
-                    1, 
-                    2, 
-                    3, 
-                    11, 
-                    100
-                ], 
-                "plurals": function(n) { return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); }
-            }, 
-            "arn": {
-                "name": "Mapudungun", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "ast": {
-                "name": "Asturian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ay": {
-                "name": "Aymar\u00e1", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "az": {
-                "name": "Azerbaijani", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "be": {
-                "name": "Belarusian", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "bg": {
-                "name": "Bulgarian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "bn": {
-                "name": "Bengali", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "bo": {
-                "name": "Tibetan", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "br": {
-                "name": "Breton", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "bs": {
-                "name": "Bosnian", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "ca": {
-                "name": "Catalan", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "cgg": {
-                "name": "Chiga", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "cs": {
-                "name": "Czech", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
-            }, 
-            "csb": {
-                "name": "Kashubian", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "cy": {
-                "name": "Welsh", 
-                "numbers": [
-                    1, 
-                    2, 
-                    3, 
-                    8
-                ], 
-                "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3); }
-            }, 
-            "da": {
-                "name": "Danish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "de": {
-                "name": "German", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "dz": {
-                "name": "Dzongkha", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "el": {
-                "name": "Greek", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "en": {
-                "name": "English", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "eo": {
-                "name": "Esperanto", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "es": {
-                "name": "Spanish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "es_ar": {
-                "name": "Argentinean Spanish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "et": {
-                "name": "Estonian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "eu": {
-                "name": "Basque", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "fa": {
-                "name": "Persian", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "fi": {
-                "name": "Finnish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "fil": {
-                "name": "Filipino", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "fo": {
-                "name": "Faroese", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "fr": {
-                "name": "French", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n >= 2); }
-            }, 
-            "fur": {
-                "name": "Friulian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "fy": {
-                "name": "Frisian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ga": {
-                "name": "Irish", 
-                "numbers": [
-                    1, 
-                    2,
-                    3,
-                    7, 
-                    11
-                ], 
-                "plurals": function(n) { return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;}
-            }, 
-            "gd": {
-                "name": "Scottish Gaelic", 
-                "numbers": [
-                    1, 
-                    2, 
-                    3,
-                    20
-                ], 
-                "plurals": function(n) { return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3); }
-            }, 
-            "gl": {
-                "name": "Galician", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "gu": {
-                "name": "Gujarati", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "gun": {
-                "name": "Gun", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "ha": {
-                "name": "Hausa", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "he": {
-                "name": "Hebrew", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "hi": {
-                "name": "Hindi", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "hr": {
-                "name": "Croatian", 
-                "numbers": [
-                    1, 
-                    2,
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "hu": {
-                "name": "Hungarian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "hy": {
-                "name": "Armenian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ia": {
-                "name": "Interlingua", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "id": {
-                "name": "Indonesian", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "is": {
-                "name": "Icelandic", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n%10!=1 || n%100==11); }
-            }, 
-            "it": {
-                "name": "Italian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ja": {
-                "name": "Japanese", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "jbo": {
-                "name": "Lojban", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "jv": {
-                "name": "Javanese", 
-                "numbers": [
-                    0, 
-                    1
-                ], 
-                "plurals": function(n) { return Number(n !== 0); }
-            }, 
-            "ka": {
-                "name": "Georgian", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "kk": {
-                "name": "Kazakh", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "km": {
-                "name": "Khmer", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "kn": {
-                "name": "Kannada", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ko": {
-                "name": "Korean", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "ku": {
-                "name": "Kurdish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "kw": {
-                "name": "Cornish", 
-                "numbers": [
-                    1, 
-                    2, 
-                    3,
-                    4
-                ], 
-                "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3); }
-            }, 
-            "ky": {
-                "name": "Kyrgyz", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "lb": {
-                "name": "Letzeburgesch", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ln": {
-                "name": "Lingala", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "lo": {
-                "name": "Lao", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "lt": {
-                "name": "Lithuanian", 
-                "numbers": [
-                    1, 
-                    2,
-                    10
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "lv": {
-                "name": "Latvian", 
-                "numbers": [
-                    1, 
-                    2, 
-                    0
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2); }
-            }, 
-            "mai": {
-                "name": "Maithili", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "mfe": {
-                "name": "Mauritian Creole", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "mg": {
-                "name": "Malagasy", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "mi": {
-                "name": "Maori", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "mk": {
-                "name": "Macedonian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n==1 || n%10==1 ? 0 : 1); }
-            }, 
-            "ml": {
-                "name": "Malayalam", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "mn": {
-                "name": "Mongolian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "mnk": {
-                "name": "Mandinka", 
-                "numbers": [
-                    0, 
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(0 ? 0 : n==1 ? 1 : 2); }
-            }, 
-            "mr": {
-                "name": "Marathi", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ms": {
-                "name": "Malay", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "mt": {
-                "name": "Maltese", 
-                "numbers": [
-                    1, 
-                    2, 
-                    11, 
-                    20
-                ], 
-                "plurals": function(n) { return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); }
-            }, 
-            "nah": {
-                "name": "Nahuatl", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "nap": {
-                "name": "Neapolitan", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "nb": {
-                "name": "Norwegian Bokmal", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ne": {
-                "name": "Nepali", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "nl": {
-                "name": "Dutch", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "nn": {
-                "name": "Norwegian Nynorsk", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "no": {
-                "name": "Norwegian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "nso": {
-                "name": "Northern Sotho", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "oc": {
-                "name": "Occitan", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "or": {
-                "name": "Oriya", 
-                "numbers": [
-                    2, 
-                    1
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "pa": {
-                "name": "Punjabi", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "pap": {
-                "name": "Papiamento", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "pl": {
-                "name": "Polish", 
-                "numbers": [
-                    1, 
-                    2,
-                    5
-                ], 
-                "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "pms": {
-                "name": "Piemontese", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ps": {
-                "name": "Pashto", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "pt": {
-                "name": "Portuguese", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "pt_br": {
-                "name": "Brazilian Portuguese", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "rm": {
-                "name": "Romansh", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ro": {
-                "name": "Romanian", 
-                "numbers": [
-                    1, 
-                    2,
-                    20
-                ], 
-                "plurals": function(n) { return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); }
-            }, 
-            "ru": {
-                "name": "Russian", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "sah": {
-                "name": "Yakut", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "sco": {
-                "name": "Scots", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "se": {
-                "name": "Northern Sami", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "si": {
-                "name": "Sinhala", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "sk": {
-                "name": "Slovak", 
-                "numbers": [
-                    1, 
-                    2, 
-                    5
-                ], 
-                "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
-            }, 
-            "sl": {
-                "name": "Slovenian", 
-                "numbers": [
-                    5, 
-                    1, 
-                    2, 
-                    3
-                ], 
-                "plurals": function(n) { return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
-            }, 
-            "so": {
-                "name": "Somali", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "son": {
-                "name": "Songhay", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "sq": {
-                "name": "Albanian", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "sr": {
-                "name": "Serbian", 
-                "numbers": [
-                    1, 
-                    2,
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "su": {
-                "name": "Sundanese", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "sv": {
-                "name": "Swedish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "sw": {
-                "name": "Swahili", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "ta": {
-                "name": "Tamil", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "te": {
-                "name": "Telugu", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "tg": {
-                "name": "Tajik", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "th": {
-                "name": "Thai", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "ti": {
-                "name": "Tigrinya", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "tk": {
-                "name": "Turkmen", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "tr": {
-                "name": "Turkish", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "tt": {
-                "name": "Tatar", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "ug": {
-                "name": "Uyghur", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "uk": {
-                "name": "Ukrainian", 
-                "numbers": [
-                    1, 
-                    2,
-                    5
-                ], 
-                "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
-            }, 
-            "ur": {
-                "name": "Urdu", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "uz": {
-                "name": "Uzbek", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "vi": {
-                "name": "Vietnamese", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "wa": {
-                "name": "Walloon", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n > 1); }
-            }, 
-            "wo": {
-                "name": "Wolof", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }, 
-            "yo": {
-                "name": "Yoruba", 
-                "numbers": [
-                    1, 
-                    2
-                ], 
-                "plurals": function(n) { return Number(n != 1); }
-            }, 
-            "zh": {
-                "name": "Chinese", 
-                "numbers": [
-                    1
-                ], 
-                "plurals": function(n) { return 0; }
-            }
-        },
-    
-        // for demonstration only sl and ar is added but you can add your own pluralExtensions
-        addRule: function(lng, obj) {
-            pluralExtensions.rules[lng] = obj;    
-        },
-    
-        setCurrentLng: function(lng) {
-            if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
-                var parts = lng.split('-');
-    
-                pluralExtensions.currentRule = {
-                    lng: lng,
-                    rule: pluralExtensions.rules[parts[0]]
-                };
-            }
-        },
-    
-        needsPlural: function(lng, count) {
-            var parts = lng.split('-');
-    
-            var ext;
-            if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
-                ext = pluralExtensions.currentRule.rule; 
-            } else {
-                ext = pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]];
-            }
-    
-            if (ext && ext.numbers.length <= 1) {
-                return false;
-            } else {
-                return this.get(lng, count) !== 1;
-            }
-        },
-    
-        get: function(lng, count) {
-            var parts = lng.split('-');
-    
-            function getResult(l, c) {
-                var ext;
-                if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
-                    ext = pluralExtensions.currentRule.rule; 
-                } else {
-                    ext = pluralExtensions.rules[l];
-                }
-                if (ext) {
-                    var i;
-                    if (ext.noAbs) {
-                        i = ext.plurals(c);
-                    } else {
-                        i = ext.plurals(Math.abs(c));
-                    }
-                    
-                    var number = ext.numbers[i];
-                    if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
-                        if (number === 2) { 
-                            number = -1; // regular plural
-                        } else if (number === 1) {
-                            number = 1; // singular
-                        }
-                    }//console.log(count + '-' + number);
-                    return number;
-                } else {
-                    return c === 1 ? '1' : '-1';
-                }
-            }
-                        
-            return getResult(parts[f.getCountyIndexOfLng(lng)], count);
-        }
-    
-    };
-    var postProcessors = {};
-    var addPostProcessor = function(name, fc) {
-        postProcessors[name] = fc;
-    };
-    // sprintf support
-    var sprintf = (function() {
-        function get_type(variable) {
-            return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
-        }
-        function str_repeat(input, multiplier) {
-            for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
-            return output.join('');
-        }
-    
-        var str_format = function() {
-            if (!str_format.cache.hasOwnProperty(arguments[0])) {
-                str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
-            }
-            return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
-        };
-    
-        str_format.format = function(parse_tree, argv) {
-            var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
-            for (i = 0; i < tree_length; i++) {
-                node_type = get_type(parse_tree[i]);
-                if (node_type === 'string') {
-                    output.push(parse_tree[i]);
-                }
-                else if (node_type === 'array') {
-                    match = parse_tree[i]; // convenience purposes only
-                    if (match[2]) { // keyword argument
-                        arg = argv[cursor];
-                        for (k = 0; k < match[2].length; k++) {
-                            if (!arg.hasOwnProperty(match[2][k])) {
-                                throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
-                            }
-                            arg = arg[match[2][k]];
-                        }
-                    }
-                    else if (match[1]) { // positional argument (explicit)
-                        arg = argv[match[1]];
-                    }
-                    else { // positional argument (implicit)
-                        arg = argv[cursor++];
-                    }
-    
-                    if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
-                        throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
-                    }
-                    switch (match[8]) {
-                        case 'b': arg = arg.toString(2); break;
-                        case 'c': arg = String.fromCharCode(arg); break;
-                        case 'd': arg = parseInt(arg, 10); break;
-                        case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
-                        case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
-                        case 'o': arg = arg.toString(8); break;
-                        case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
-                        case 'u': arg = Math.abs(arg); break;
-                        case 'x': arg = arg.toString(16); break;
-                        case 'X': arg = arg.toString(16).toUpperCase(); break;
-                    }
-                    arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
-                    pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
-                    pad_length = match[6] - String(arg).length;
-                    pad = match[6] ? str_repeat(pad_character, pad_length) : '';
-                    output.push(match[5] ? arg + pad : pad + arg);
-                }
-            }
-            return output.join('');
-        };
-    
-        str_format.cache = {};
-    
-        str_format.parse = function(fmt) {
-            var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
-            while (_fmt) {
-                if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
-                    parse_tree.push(match[0]);
-                }
-                else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
-                    parse_tree.push('%');
-                }
-                else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
-                    if (match[2]) {
-                        arg_names |= 1;
-                        var field_list = [], replacement_field = match[2], field_match = [];
-                        if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
-                            field_list.push(field_match[1]);
-                            while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
-                                if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
-                                    field_list.push(field_match[1]);
-                                }
-                                else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
-                                    field_list.push(field_match[1]);
-                                }
-                                else {
-                                    throw('[sprintf] huh?');
-                                }
-                            }
-                        }
-                        else {
-                            throw('[sprintf] huh?');
-                        }
-                        match[2] = field_list;
-                    }
-                    else {
-                        arg_names |= 2;
-                    }
-                    if (arg_names === 3) {
-                        throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
-                    }
-                    parse_tree.push(match);
-                }
-                else {
-                    throw('[sprintf] huh?');
-                }
-                _fmt = _fmt.substring(match[0].length);
-            }
-            return parse_tree;
-        };
-    
-        return str_format;
-    })();
-    
-    var vsprintf = function(fmt, argv) {
-        argv.unshift(fmt);
-        return sprintf.apply(null, argv);
-    };
-    
-    addPostProcessor("sprintf", function(val, key, opts) {
-        if (!opts.sprintf) return val;
-    
-        if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
-            return vsprintf(val, opts.sprintf);
-        } else if (typeof opts.sprintf === 'object') {
-            return sprintf(val, opts.sprintf);
-        }
-    
-        return val;
-    });
-    // public api interface
-    i18n.init = init;
-    i18n.setLng = setLng;
-    i18n.preload = preload;
-    i18n.addResourceBundle = addResourceBundle;
-    i18n.addResource = addResource;
-    i18n.addResources = addResources;
-    i18n.removeResourceBundle = removeResourceBundle;
-    i18n.loadNamespace = loadNamespace;
-    i18n.loadNamespaces = loadNamespaces;
-    i18n.setDefaultNamespace = setDefaultNamespace;
-    i18n.t = translate;
-    i18n.translate = translate;
-    i18n.exists = exists;
-    i18n.detectLanguage = f.detectLanguage;
-    i18n.pluralExtensions = pluralExtensions;
-    i18n.sync = sync;
-    i18n.functions = f;
-    i18n.lng = lng;
-    i18n.addPostProcessor = addPostProcessor;
-    i18n.options = o;
-
-})();
\ No newline at end of file
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.xml
deleted file mode 100644
index fea41d81c6..0000000000
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_plugin_i18next_js.xml
+++ /dev/null
@@ -1,320 +0,0 @@
-<?xml version="1.0"?>
-<ZopeData>
-  <record id="1" aka="AAAAAAAAAAE=">
-    <pickle>
-      <global name="Web Script" module="erp5.portal_type"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>_Access_contents_information_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Anonymous</string>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Associate</string>
-                <string>Auditor</string>
-                <string>Manager</string>
-                <string>Owner</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Add_portal_content_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Change_local_roles_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Assignor</string>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Modify_portal_content_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_View_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Anonymous</string>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Associate</string>
-                <string>Auditor</string>
-                <string>Manager</string>
-                <string>Owner</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>content_md5</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>default_reference</string> </key>
-            <value> <string>i18next.js</string> </value>
-        </item>
-        <item>
-            <key> <string>description</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>id</string> </key>
-            <value> <string>rjs_plugin_i18next_js</string> </value>
-        </item>
-        <item>
-            <key> <string>language</string> </key>
-            <value> <string>en</string> </value>
-        </item>
-        <item>
-            <key> <string>portal_type</string> </key>
-            <value> <string>Web Script</string> </value>
-        </item>
-        <item>
-            <key> <string>short_title</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>title</string> </key>
-            <value> <string>plugin i18next JS</string> </value>
-        </item>
-        <item>
-            <key> <string>version</string> </key>
-            <value> <string>1.7.4</string> </value>
-        </item>
-        <item>
-            <key> <string>workflow_history</string> </key>
-            <value>
-              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
-            </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-  <record id="2" aka="AAAAAAAAAAI=">
-    <pickle>
-      <global name="PersistentMapping" module="Persistence.mapping"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>data</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>document_publication_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
-                    </value>
-                </item>
-                <item>
-                    <key> <string>edit_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
-                    </value>
-                </item>
-                <item>
-                    <key> <string>processing_status_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
-                    </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-  <record id="3" aka="AAAAAAAAAAM=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>publish_alive</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>super_sven</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1418835142.27</float>
-                        <string>GMT</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-            <item>
-                <key> <string>validation_state</string> </key>
-                <value> <string>published_alive</string> </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-  <record id="4" aka="AAAAAAAAAAQ=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>edit</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>super_sven</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value>
-                  <none/>
-                </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>serial</string> </key>
-                <value> <string>939.44304.41368.21111</string> </value>
-            </item>
-            <item>
-                <key> <string>state</string> </key>
-                <value> <string>current</string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1418834941.27</float>
-                        <string>GMT</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-  <record id="5" aka="AAAAAAAAAAU=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>detect_converted_file</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>super_sven</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>external_processing_state</string> </key>
-                <value> <string>converted</string> </value>
-            </item>
-            <item>
-                <key> <string>serial</string> </key>
-                <value> <string>0.0.0.0</string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1418834767.8</float>
-                        <string>GMT</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_site_module/renderjs_runner.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_site_module/renderjs_runner.xml
index c905aeaf99..7b0234c836 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_site_module/renderjs_runner.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_site_module/renderjs_runner.xml
@@ -397,7 +397,7 @@
         </item>
         <item>
             <key> <string>static_language_selection</string> </key>
-            <value> <int>0</int> </value>
+            <value> <int>1</int> </value>
         </item>
         <item>
             <key> <string>title</string> </key>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.py b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.py
new file mode 100644
index 0000000000..b6fbf69dfa
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.py
@@ -0,0 +1,54 @@
+import re
+import json
+
+
+
+Base_translateString = context.Base_translateString
+#(data-i18n)=["']{{((?:.(?!["']?(?:\S+)=|[>"']))+.)}}["']
+attribute_filter_re = re.compile(r"""(data-i18n)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?""")
+
+tmp_re = re.compile(r"""/[{}]/g, """"")
+
+
+translate_word = []
+
+web_page_list = context.Base_getListFileFromAppcache(only_html=1)
+for web_page in web_page_list:
+  web_page = context.web_page_module.searchFolder(portal_type='Web Page',reference=web_page)[0]
+  data = attribute_filter_re.findall(web_page.getTextContent())
+  for attribute in data:
+    a = re.sub(r'[{|}]', "", attribute[1])
+    a = re.sub(r'\[.*?\]', "", a)
+    if a:
+      translate_word.append(a)
+
+translate_word =  list(set(translate_word))
+
+
+language_list = context.getAvailableLanguageSet()
+
+content = """
+/*globals window*/\n
+/*jslint indent: 2, nomen: true, maxlen: 80*/\n
+(function (window) {\n
+  "use strict";\n
+"""
+
+tmp = {}
+
+for language in language_list:
+  tmp[language] = {}
+  for word in translate_word:
+    tmp[language][word] = Base_translateString(word, lang = language)
+
+
+
+content += "  window.translation_data = " + json.dumps(tmp, indent=3, ensure_ascii=False, separators=(',', ': '))
+content += ";\n}(window));"
+#return json.dumps(tmp, indent=3, ensure_ascii=False, separators=(',', ': '))
+translation_data_file=context.web_page_module.searchFolder(portal_type='Web Script',reference=translation_data_file)[0]
+translation_data_file.edit(text_content = content)
+
+if batch_mode:
+  return 'done'
+return context.Base_redirect('view', keep_items=dict(portal_status_message=Base_translateString("Translation Data Create")))
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.xml b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.xml
new file mode 100644
index 0000000000..faf1b9e6e5
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_createTranslateData.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string> translation_data_file, batch_mode=0</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Base_createTranslateData</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.py b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.py
new file mode 100644
index 0000000000..abfbeb8f01
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.py
@@ -0,0 +1,21 @@
+appcache_file = context.getLayoutProperty("configuration_manifest_url", default="gadget_erp5.appcache")
+
+
+text_content = context.web_page_module.searchFolder(
+  portal_type= 'Web Manifest',
+  reference = appcache_file)[0].getTextContent()
+
+translation_data_file = []
+file_list = []
+for file in text_content.split('\n'):
+  file = file.split('/')[-1]
+  if file.endswith('.html'):
+    file_list.append(file)
+    continue
+
+  if file.endswith('.js') and not only_html:
+    if file.endswith('translation_data.js'):
+      translation_data_file = [file]
+      continue
+    file_list.append(file)
+return translation_data_file + file_list
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.xml b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.xml
new file mode 100644
index 0000000000..f7d497e57e
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/Base_getListFileFromAppcache.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string>only_html = 0</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Base_getListFileFromAppcache</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData.xml b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData.xml
new file mode 100644
index 0000000000..5661006a6e
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ERP5 Form" module="erp5.portal_type"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_objects</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>action</string> </key>
+            <value> <string>Base_createTranslateData</string> </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>edit_order</string> </key>
+            <value>
+              <list/>
+            </value>
+        </item>
+        <item>
+            <key> <string>encoding</string> </key>
+            <value> <string>UTF-8</string> </value>
+        </item>
+        <item>
+            <key> <string>enctype</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>group_list</string> </key>
+            <value>
+              <list>
+                <string>left</string>
+                <string>right</string>
+                <string>center</string>
+                <string>bottom</string>
+                <string>hidden</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>groups</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>bottom</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>center</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>left</string> </key>
+                    <value>
+                      <list>
+                        <string>your_translation_data_file</string>
+                      </list>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>right</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>WebSite_createTranslationData</string> </value>
+        </item>
+        <item>
+            <key> <string>method</string> </key>
+            <value> <string>POST</string> </value>
+        </item>
+        <item>
+            <key> <string>name</string> </key>
+            <value> <string>WebSite_createTranslationData</string> </value>
+        </item>
+        <item>
+            <key> <string>pt</string> </key>
+            <value> <string>form_dialog</string> </value>
+        </item>
+        <item>
+            <key> <string>row_length</string> </key>
+            <value> <int>4</int> </value>
+        </item>
+        <item>
+            <key> <string>stored_encoding</string> </key>
+            <value> <string>UTF-8</string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>Create Translation Data</string> </value>
+        </item>
+        <item>
+            <key> <string>unicode_mode</string> </key>
+            <value> <int>0</int> </value>
+        </item>
+        <item>
+            <key> <string>update_action</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>update_action_title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData/your_translation_data_file.xml b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData/your_translation_data_file.xml
new file mode 100644
index 0000000000..e085940ec6
--- /dev/null
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs/WebSite_createTranslationData/your_translation_data_file.xml
@@ -0,0 +1,277 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ListField" module="Products.Formulator.StandardFields"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>your_translation_data_file</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+                <item>
+                    <key> <string>required_not_found</string> </key>
+                    <value> <string>Input is required but no input given.</string> </value>
+                </item>
+                <item>
+                    <key> <string>unknown_selection</string> </key>
+                    <value> <string>You selected an item that was not in the list.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <int>5</int> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>Translation Data File</string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="TALESMethod" module="Products.Formulator.TALESField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_text</string> </key>
+            <value> <string>python: [ (x,x) for x in here.Base_getListFileFromAppcache()]</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSection_renderDefaultPageAsGadget.py b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSection_renderDefaultPageAsGadget.py
index 69337ff015..1cc9e79881 100644
--- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSection_renderDefaultPageAsGadget.py
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSection_renderDefaultPageAsGadget.py
@@ -1,3 +1,6 @@
+import json
+import re
+
 if REQUEST is None:
   REQUEST = context.REQUEST
 if response is None:
@@ -6,6 +9,22 @@ if response is None:
 default_web_page = context
 web_section = REQUEST.get("current_web_section")
 
+available_language_set = web_section.getLayoutProperty("available_language_set", default=['en'])
+portal = context.getPortalObject()
+default_language = web_section.getLayoutProperty("default_available_language", default='en')
+website_url_set = {}
+
+#simplify code of Base_doLanguage, can't ues Base_doLanguage directly
+root_website_url = web_section.getOriginalDocument().absolute_url()
+website_url_pattern = r'^%s(?:%s)*(/|$)' % (
+  re.escape(root_website_url),
+  '|'.join('/' + re.escape(x) for x in available_language_set))
+
+for language in available_language_set:
+  if language == default_language:
+    website_url_set[language] = re.sub(website_url_pattern, r'%s/\1' % root_website_url, web_section.absolute_url())
+  else:
+    website_url_set[language]=  re.sub(website_url_pattern, r'%s/%s/\1' % (root_website_url, language), web_section.absolute_url())
 
 return default_web_page.WebPage_viewAsWeb(mapping_dict={
   "frontpage_gadget": web_section.getLayoutProperty("configuration_frontpage_gadget_url", default="worklist"),
@@ -18,5 +37,8 @@ return default_web_page.WebPage_viewAsWeb(mapping_dict={
   "header_gadget": web_section.getLayoutProperty("configuration_header_gadget_url", default="gadget_erp5_header.html"),
   "jio_gadget": web_section.getLayoutProperty("configuration_jio_gadget_url", default="gadget_jio.html"),
   "translation_gadget": web_section.getLayoutProperty("configuration_translation_gadget_url", default="gadget_translation.html"),
-  "manifest_url": web_section.getLayoutProperty("configuration_manifest_url", default="gadget_erp5.appcache")
+  "manifest_url": web_section.getLayoutProperty("configuration_manifest_url", default="gadget_erp5.appcache"),
+  "language_map": json.dumps({tmp['id']: portal.Base_translateString(tmp['title'], lang = tmp['id']) for tmp in portal.Localizer.get_languages_map() if tmp['id'] in available_language_set}),
+  "default_selected_language":  portal.Localizer.get_selected_language(),
+  "website_url_set": json.dumps(website_url_set),
 })
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_login.py b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_login.py
index 979aba2a6e..bb92dc8c51 100644
--- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_login.py
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_login.py
@@ -6,7 +6,8 @@ from ZTUtils import make_query
 portal = context.getPortalObject()
 
 if (came_from is None):
-  came_from = context.getPermanentURL(context.getWebSiteValue())
+  #XXX Hardcoded for JS app's url end with '/'
+  came_from = "%s/" % context.getPermanentURL(context.getWebSiteValue())
 
 portal.portal_skins.updateSkinCookie()
 portal.setupCurrentSkin(REQUEST)
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_viewRecoverAccount.zpt b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_viewRecoverAccount.zpt
index 913a3bb168..2bdd858b9a 100644
--- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_viewRecoverAccount.zpt
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/WebSite_viewRecoverAccount.zpt
@@ -10,7 +10,7 @@
 
     <div data-gadget-scope='header'>
       <div class="ui-header">
-        <h1><span>Recover your account</span></h1>
+        <h1><span i18n:domain="ui" i18n:translate="">Recover your account</span></h1>
       </div>
     </div>
 
@@ -28,13 +28,13 @@
         <section>
           <form method="post" tal:attributes="action python: context.absolute_url()">
             <div class="ui-field-contain">
-              <label data-i18n="Login">Login<span></span></label>
+              <label i18n:domain="ui" i18n:translate="">Login</label>
               <div><input autofocus type="text" name="user_login" value="" required=""></div>
             </div>
             <br/>
             <div class="ui-field-contain">
               <label></label>
-              <div><input type="submit" data-i18n="[value]Validate" value="Validate" tal:attributes="name python: '%s:method' % (form_action, )"/></div>
+              <div><input type="submit" value="Validate" i18n:attributes="value" i18n:domain="ui" tal:attributes="name python: '%s:method' % (form_action, )"/></div>
             </div>
 
             <input type="hidden" name="url" tal:attributes="value python: context.absolute_url()" />
diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.zpt b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.zpt
index 1219e32020..09fc4924b4 100644
--- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.zpt
+++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/login_form.zpt
@@ -10,7 +10,7 @@
 
     <div data-gadget-scope='header'>
       <div class="ui-header">
-        <h1><span>Connect</span></h1>
+        <h1><span i18n:domain="ui" i18n:translate="">Connect</span></h1>
       </div>
     </div>
 
@@ -34,22 +34,22 @@
           <form method="post" tal:attributes="action python: '%s/' % context.absolute_url()">
 
             <div class="ui-field-contain">
-              <label data-i18n="Login">Login<span></span></label>
+              <label i18n:domain="ui" i18n:translate="" >Login</label>
               <div><input autofocus type="text" name="__ac_name" value="" required=""></div>
             </div>
             <div class="ui-field-contain">
-              <label data-i18n="Password">Password<span></span></label>
+              <label i18n:domain="ui" i18n:translate="" >Password</label>
               <div><input type="password" name="__ac_password" value="" required=""></div>
             </div>
             <div class="ui-field-contain">
               <label></label>
               <div tal:define="absolute_url python:context.absolute_url()">
-                <a tal:attributes="href python: '%s/WebSite_viewRecoverAccount?came_from=%s' % (absolute_url, absolute_url)">I forgot my password!</a>
+                <a  i18n:domain="ui" i18n:translate="" tal:attributes="href python: '%s/WebSite_viewRecoverAccount?came_from=%s' % (absolute_url, absolute_url)">I forgot my password!</a>
               </div>
             </div><br/>
             <div class="ui-field-contain">
               <label></label>
-              <div><input type="submit" value="Login" tal:attributes="name python: '%s:method' % (form_action, )"/></div>
+              <div><input type="submit" value='Login' i18n:attributes="value" i18n:domain="ui"  tal:attributes="name python: '%s:method' % (form_action, )"/></div>
             </div>
 
 
diff --git a/bt5/erp5_web_renderjs_ui/bt/template_action_path_list b/bt5/erp5_web_renderjs_ui/bt/template_action_path_list
index 1f8bcd88d0..341dd734bf 100644
--- a/bt5/erp5_web_renderjs_ui/bt/template_action_path_list
+++ b/bt5/erp5_web_renderjs_ui/bt/template_action_path_list
@@ -7,6 +7,7 @@ Web Script | view
 Web Script | view_editor
 Web Script | view_syntax
 Web Script | web_view
+Web Site | create_translation_data
 Web Style | version_view
 Web Style | view
 Web Style | view_editor
-- 
2.30.9