Add i18n support to the main world

The main world didn't have access to the chrome.i18n API. This CL adds
support to access the API from the main world by using a bridge between
the main world and a server running in a content script.

Bug: twpowertools:157

Change-Id: I5b93f92156e9f658428214252c209570337c23a4
diff --git a/src/common/mainWorldI18n/Client.js b/src/common/mainWorldI18n/Client.js
new file mode 100644
index 0000000..b1b8286
--- /dev/null
+++ b/src/common/mainWorldI18n/Client.js
@@ -0,0 +1,20 @@
+import MainWorldContentScriptBridgeClient from '../mainWorldContentScriptBridge/Client.js';
+
+import {kCSTarget, kMWTarget} from './consts.js';
+
+// Main World i18n client (used in scripts injected into the Main World (MW) to
+// use the chrome.i18n API).
+export default class MWI18nClient extends MainWorldContentScriptBridgeClient {
+  constructor(timeout) {
+    super(kCSTarget, kMWTarget, timeout);
+  }
+
+  async getMessage(messageName, substitutions, options) {
+    return this._sendRequest(
+        'getMessage', {messageName, substitutions, options});
+  }
+
+  async getUILanguage() {
+    return this._sendRequest('getUILanguage', {});
+  }
+}
diff --git a/src/common/mainWorldI18n/Server.js b/src/common/mainWorldI18n/Server.js
new file mode 100644
index 0000000..7299ee9
--- /dev/null
+++ b/src/common/mainWorldI18n/Server.js
@@ -0,0 +1,29 @@
+import MainWorldContentScriptBridgeServer from '../mainWorldContentScriptBridge/Server.js';
+
+import {kCSTarget, kMWTarget} from './consts.js';
+
+// Main World i18n server (used in content scripts to be able to serve the
+// chrome.i18n API to Main World (MW) scripts).
+export default class MWI18nServer extends MainWorldContentScriptBridgeServer {
+  constructor() {
+    super(kCSTarget, kMWTarget);
+    this.setUpHandler(this.handleMessage);
+  }
+
+  handleMessage(uuid, action, request) {
+    switch (action) {
+      case 'getMessage':
+        var response = chrome.i18n.getMessage(
+            request.messageName, request.substitutions, request.options);
+        this._respond(uuid, response);
+        return;
+
+      case 'getUILanguage':
+        this._respond(uuid, chrome.i18n.getUILanguage());
+        return;
+
+      default:
+        console.error(`[MWI18nServer] Invalid action received (${action})`);
+    }
+  }
+}
diff --git a/src/common/mainWorldI18n/consts.js b/src/common/mainWorldI18n/consts.js
new file mode 100644
index 0000000..d022bc2
--- /dev/null
+++ b/src/common/mainWorldI18n/consts.js
@@ -0,0 +1,2 @@
+export const kCSTarget = 'TWPT-I18n-CS';
+export const kMWTarget = 'TWPT-I18n-MW';
diff --git a/src/contentScripts/communityConsole/start.js b/src/contentScripts/communityConsole/start.js
index f364626..7abbeaa 100644
--- a/src/contentScripts/communityConsole/start.js
+++ b/src/contentScripts/communityConsole/start.js
@@ -1,4 +1,5 @@
 import {injectScript, injectStylesheet} from '../../common/contentScriptsUtils.js';
+import MWI18nServer from '../../common/mainWorldI18n/Server.js';
 import MWOptionsWatcherServer from '../../common/mainWorldOptionsWatcher/Server.js';
 import {getOptions} from '../../common/optionsUtils.js';
 import {kCSTarget, kMWTarget} from '../../xhrInterceptor/responseModifiers/index.js';
@@ -78,4 +79,5 @@
   }
 
   new MWOptionsWatcherServer(kCSTarget, kMWTarget);
+  new MWI18nServer();
 });