Browse Source

Implements basic multi language support.

j8
hristoterezov 10 years ago
parent
commit
3032ea7684

+ 2
- 1
Makefile View File

1
 BROWSERIFY = browserify
1
 BROWSERIFY = browserify
2
-GLOBAL_FLAGS = -e
2
+GLOBAL_FLAGS = -x jquery -e
3
 OUTPUT_DIR = .
3
 OUTPUT_DIR = .
4
 DEPLOY_DIR = libs
4
 DEPLOY_DIR = libs
5
 
5
 
21
 
21
 
22
 deploy:
22
 deploy:
23
 	@mkdir -p $(DEPLOY_DIR) && cp $(OUTPUT_DIR)/*.bundle.js $(DEPLOY_DIR)
23
 	@mkdir -p $(DEPLOY_DIR) && cp $(OUTPUT_DIR)/*.bundle.js $(DEPLOY_DIR)
24
+	

+ 3
- 0
app.js View File

13
         this.desktopsharing = require("./modules/desktopsharing/desktopsharing");
13
         this.desktopsharing = require("./modules/desktopsharing/desktopsharing");
14
         this.xmpp = require("./modules/xmpp/xmpp");
14
         this.xmpp = require("./modules/xmpp/xmpp");
15
         this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut");
15
         this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut");
16
+        this.translation = require("./modules/translation/translation");
16
     }
17
     }
17
 };
18
 };
18
 
19
 
34
 
35
 
35
     APP.init();
36
     APP.init();
36
 
37
 
38
+    APP.translation.init();
39
+
37
     if(APP.API.isEnabled())
40
     if(APP.API.isEnabled())
38
         APP.API.init();
41
         APP.API.init();
39
 
42
 

+ 5
- 1
css/settingsmenu.css View File

3
     color: #00ccff;
3
     color: #00ccff;
4
 }
4
 }
5
 
5
 
6
-#settingsmenu input {
6
+#settingsmenu input, select {
7
     margin-top: 10px;
7
     margin-top: 10px;
8
     margin-left: 10%;
8
     margin-left: 10%;
9
     width: 80%;
9
     width: 80%;
43
 #settingsmenu .icon-settings {
43
 #settingsmenu .icon-settings {
44
     padding: 34px;
44
     padding: 34px;
45
 }
45
 }
46
+
47
+#languages_selectbox{
48
+    height: 40px;
49
+}

+ 50
- 65
index.html View File

19
     <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
19
     <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
20
     <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
20
     <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
21
     <script src="interface_config.js?v=5"></script>
21
     <script src="interface_config.js?v=5"></script>
22
-    <script src="libs/app.bundle.js?v=6"></script>
22
+    <script src="libs/app.bundle.js?v=7"></script>
23
 
23
 
24
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
24
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
25
     <link rel="stylesheet" href="css/font.css?v=6"/>
25
     <link rel="stylesheet" href="css/font.css?v=6"/>
52
             <a target="_new">
52
             <a target="_new">
53
                 <div class="watermark rightwatermark"></div>
53
                 <div class="watermark rightwatermark"></div>
54
             </a>
54
             </a>
55
-            <a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a>
55
+            <a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
56
 
56
 
57
             <div id="enter_room_container">
57
             <div id="enter_room_container">
58
                     <div id="enter_room_form" >
58
                     <div id="enter_room_form" >
59
                         <div id="domain_name"></div>
59
                         <div id="domain_name"></div>
60
                         <div id="enter_room">
60
                         <div id="enter_room">
61
-                            <input id="enter_room_field" type="text" autofocus placeholder="Enter room name" />
61
+                            <input id="enter_room_field" type="text" autofocus data-i18n="[placeholder]welcomepage.roomname" placeholder="Enter room name" />
62
                             <div class="icon-reload" id="reload_roomname"></div>
62
                             <div class="icon-reload" id="reload_roomname"></div>
63
-                            <input id="enter_room_button" type="button" value="GO" />
63
+                            <input id="enter_room_button" type="button" data-i18n="[value]welcomepage.go" value="GO" />
64
 
64
 
65
                         </div>
65
                         </div>
66
                     </div>
66
                     </div>
67
             </div>
67
             </div>
68
             <div id="brand_header"></div>
68
             <div id="brand_header"></div>
69
             <input type='checkbox' name='checkbox' id="disable_welcome"/>
69
             <input type='checkbox' name='checkbox' id="disable_welcome"/>
70
-            <label for="disable_welcome" class="disable_welcome_position">Don't show this page next time I enter</label>
70
+            <label for="disable_welcome" class="disable_welcome_position" data-i18n="welcomepage.disable"></label>
71
             <div id="header_text"></div>
71
             <div id="header_text"></div>
72
         </div>
72
         </div>
73
         <div id="welcome_page_main">
73
         <div id="welcome_page_main">
74
             <div id="features">
74
             <div id="features">
75
                 <div class="feature_row">
75
                 <div class="feature_row">
76
                     <div class="feature_holder">
76
                     <div class="feature_holder">
77
-                        <div class="feature_icon">Simple to use</div>
78
-                        <div class="feature_description">
79
-                            No downloads required. <span name="appName"></span> works directly within your browser. Simply share your conference URL with others to get started.
77
+                        <div class="feature_icon" data-i18n="welcomepage.feature1.title" ></div>
78
+                        <div class="feature_description" data-i18n="welcomepage.feature1.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
80
                         </div>
79
                         </div>
81
                     </div>
80
                     </div>
82
                     <div class="feature_holder">
81
                     <div class="feature_holder">
83
-                        <div class="feature_icon">Low bandwidth</div>
84
-                        <div class="feature_description">
85
-                            Multi-party video conferences work with as little as 128Kbps. Screen-sharing and audio-only conferences are possible with far less.
82
+                        <div class="feature_icon" data-i18n="welcomepage.feature2.title" ></div>
83
+                        <div class="feature_description" data-i18n="welcomepage.feature2.content">
86
                         </div>
84
                         </div>
87
                     </div>
85
                     </div>
88
                     <div class="feature_holder">
86
                     <div class="feature_holder">
89
-                        <div class="feature_icon">Open source</div>
90
-                        <div class="feature_description">
91
-                            <span name="appName"></span> is licensed under MIT. You are free to download, use, modify, and share them as per these licenses.
87
+                        <div class="feature_icon" data-i18n="welcomepage.feature3.title" ></div>
88
+                        <div class="feature_description" data-i18n="welcomepage.feature3.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
92
                         </div>
89
                         </div>
93
                     </div>
90
                     </div>
94
                     <div class="feature_holder">
91
                     <div class="feature_holder">
95
-                        <div class="feature_icon">Unlimited users</div>
96
-                        <div class="feature_description">
97
-                            There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors.
92
+                        <div class="feature_icon" data-i18n="welcomepage.feature4.title" ></div>
93
+                        <div class="feature_description" data-i18n="welcomepage.feature4.content">
98
                         </div>
94
                         </div>
99
                     </div>
95
                     </div>
100
                 </div>
96
                 </div>
101
                 <div class="feature_row">
97
                 <div class="feature_row">
102
                     <div class="feature_holder">
98
                     <div class="feature_holder">
103
-                        <div class="feature_icon">Screen sharing</div>
104
-                        <div class="feature_description">
105
-                            It's easy to share your screen with others. <span name="appName"></span> is ideal for on-line presentations, lectures, and tech support sessions.
106
-                        </div>
99
+                            <div class="feature_icon" data-i18n="welcomepage.feature5.title" ></div>
100
+                            <div class="feature_description" data-i18n="welcomepage.feature5.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
101
+                            </div>
107
                     </div>
102
                     </div>
108
                     <div class="feature_holder">
103
                     <div class="feature_holder">
109
-                        <div class="feature_icon">Secure rooms</div>
110
-                        <div class="feature_description">
111
-                            Need some privacy? <span name="appName"></span> conference rooms can be secured with a password in order to exclude unwanted guests and prevent interruptions.
112
-                        </div>
104
+                            <div class="feature_icon" data-i18n="welcomepage.feature6.title" ></div>
105
+                            <div class="feature_description" data-i18n="welcomepage.feature6.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
106
+                            </div>
113
                     </div>
107
                     </div>
114
                     <div class="feature_holder">
108
                     <div class="feature_holder">
115
-                        <div class="feature_icon">Shared notes</div>
116
-                        <div class="feature_description">
117
-                            <span name="appName"></span> features Etherpad, a real-time collaborative text editor that's great for meeting minutes, writing articles, and more.
118
-                        </div>
109
+                            <div class="feature_icon" data-i18n="welcomepage.feature7.title" ></div>
110
+                            <div class="feature_description" data-i18n="welcomepage.feature7.content" data-i18n-options='{ "postProcess": "resolveAppName" }'></div>
119
                     </div>
111
                     </div>
120
                     <div class="feature_holder">
112
                     <div class="feature_holder">
121
-                        <div class="feature_icon">Usage statistics</div>
122
-                        <div class="feature_description">
123
-                            Learn about your users through easy integration with Piwik, Google Analytics, and other usage monitoring and statistics systems.
124
-                        </div>
113
+                            <div class="feature_icon" data-i18n="welcomepage.feature8.title" ></div>
114
+                            <div class="feature_description" data-i18n="welcomepage.feature8.content"></div>
125
                     </div>
115
                     </div>
126
                 </div>
116
                 </div>
127
             </div>
117
             </div>
131
         <div style="position: relative;" id="header_container">
121
         <div style="position: relative;" id="header_container">
132
             <div id="header">
122
             <div id="header">
133
                 <span id="toolbar">
123
                 <span id="toolbar">
134
-                    <a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" content="Mute / Unmute">
124
+                    <a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
135
                         <i id="mute" class="icon-microphone"></i>
125
                         <i id="mute" class="icon-microphone"></i>
136
                     </a>
126
                     </a>
137
                     <div class="header_button_separator"></div>
127
                     <div class="header_button_separator"></div>
138
-                    <a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" content="Start / stop camera">
128
+                    <a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" data-i18n="[content]toolbar.videomute" content="Start / stop camera">
139
                         <i id="video" class="icon-camera"></i>
129
                         <i id="video" class="icon-camera"></i>
140
                     </a>
130
                     </a>
141
                     <span id="authentication" style="display: none">
131
                     <span id="authentication" style="display: none">
142
                         <div class="header_button_separator"></div>
132
                         <div class="header_button_separator"></div>
143
-                        <a class="button" id="toolbar_button_authentication" data-container="body" data-toggle="popover" data-placement="bottom" content="Authenticate">
133
+                        <a class="button" id="toolbar_button_authentication" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.authenticate" content="Authenticate">
144
                             <i id="authButton" class="icon-avatar"></i>
134
                             <i id="authButton" class="icon-avatar"></i>
145
                         </a>
135
                         </a>
146
                     </span>
136
                     </span>
147
                     <span id="recording" style="display: none">
137
                     <span id="recording" style="display: none">
148
                         <div class="header_button_separator"></div>
138
                         <div class="header_button_separator"></div>
149
-                        <a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" content="Record">
139
+                        <a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.record" content="Record">
150
                             <i id="recordButton" class="icon-recEnable"></i>
140
                             <i id="recordButton" class="icon-recEnable"></i>
151
                         </a>
141
                         </a>
152
                     </span>
142
                     </span>
153
                     <div class="header_button_separator"></div>
143
                     <div class="header_button_separator"></div>
154
-                    <a class="button" id="toolbar_button_security" data-container="body" data-toggle="popover" data-placement="bottom" content="Lock / unlock room">
144
+                    <a class="button" id="toolbar_button_security" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.lock" content="Lock / unlock room">
155
                         <i id="lockIcon" class="icon-security"></i>
145
                         <i id="lockIcon" class="icon-security"></i>
156
                     </a>
146
                     </a>
157
                     <div class="header_button_separator"></div>
147
                     <div class="header_button_separator"></div>
158
-                    <a class="button" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="bottom" content="Invite others">
148
+                    <a class="button" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.invite" content="Invite others">
159
                         <i class="icon-link"></i>
149
                         <i class="icon-link"></i>
160
                     </a>
150
                     </a>
161
                     <div class="header_button_separator"></div>
151
                     <div class="header_button_separator"></div>
162
                     <span class="toolbar_span">
152
                     <span class="toolbar_span">
163
-                        <a class="button" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" content="Open / close chat">
153
+                        <a class="button" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" data-i18n="[content]toolbar.chat" content="Open / close chat">
164
                             <i id="chatButton" class="icon-chat">
154
                             <i id="chatButton" class="icon-chat">
165
                                 <span id="unreadMessages"></span>
155
                                 <span id="unreadMessages"></span>
166
                             </i>
156
                             </i>
168
                     </span>
158
                     </span>
169
                     <span id="prezi_button">
159
                     <span id="prezi_button">
170
                         <div class="header_button_separator"></div>
160
                         <div class="header_button_separator"></div>
171
-                        <a class="button" id="toolbar_button_prezi" data-container="body" data-toggle="popover" data-placement="bottom" content="Share Prezi">
161
+                        <a class="button" id="toolbar_button_prezi" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.prezi" content="Share Prezi">
172
                             <i class="icon-prezi"></i>
162
                             <i class="icon-prezi"></i>
173
                         </a>
163
                         </a>
174
                     </span>
164
                     </span>
175
                     <span id="etherpadButton">
165
                     <span id="etherpadButton">
176
                         <div class="header_button_separator"></div>
166
                         <div class="header_button_separator"></div>
177
-                        <a class="button" id="toolbar_button_etherpad" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document">
167
+                        <a class="button" id="toolbar_button_etherpad" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document" data-i18n="[content]toolbar.etherpad">
178
                             <i class="icon-share-doc"></i>
168
                             <i class="icon-share-doc"></i>
179
                         </a>
169
                         </a>
180
                     </span>
170
                     </span>
181
                     <div class="header_button_separator"></div>
171
                     <div class="header_button_separator"></div>
182
                     <span id="desktopsharing" style="display: none">
172
                     <span id="desktopsharing" style="display: none">
183
-                        <a class="button" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen">
173
+                        <a class="button" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen" data-i18n="[content]toolbar.sharescreen">
184
                             <i class="icon-share-desktop"></i>
174
                             <i class="icon-share-desktop"></i>
185
                         </a>
175
                         </a>
186
                     </span>
176
                     </span>
187
                     <div class="header_button_separator"></div>
177
                     <div class="header_button_separator"></div>
188
-                    <a class="button" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen">
178
+                    <a class="button" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen" data-i18n="[content]toolbar.fullscreen">
189
                         <i id="fullScreen" class="icon-full-screen"></i>
179
                         <i id="fullScreen" class="icon-full-screen"></i>
190
                     </a>
180
                     </a>
191
                     <span id="sipCallButton" style="display: none">
181
                     <span id="sipCallButton" style="display: none">
192
                         <div class="header_button_separator"></div>
182
                         <div class="header_button_separator"></div>
193
-                        <a class="button" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number">
183
+                        <a class="button" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number" data-i18n="[content]toolbar.sip">
194
                             <i class="icon-telephone"></i></a>
184
                             <i class="icon-telephone"></i></a>
195
                     </span>
185
                     </span>
196
                     <div class="header_button_separator"></div>
186
                     <div class="header_button_separator"></div>
197
-                    <a class="button" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" >
187
+                    <a class="button" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" data-i18n="[content]toolbar.Settings">
198
                         <i id="settingsButton" class="icon-settings"></i>
188
                         <i id="settingsButton" class="icon-settings"></i>
199
                     </a>
189
                     </a>
200
                     <div class="header_button_separator"></div>
190
                     <div class="header_button_separator"></div>
201
                     <span id="hangup">
191
                     <span id="hangup">
202
-                        <a class="button" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up">
192
+                        <a class="button" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" data-i18n="[content]toolbar.hangup">
203
                             <i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i>
193
                             <i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i>
204
                         </a>
194
                         </a>
205
                     </span>
195
                     </span>
208
             <div id="subject"></div>
198
             <div id="subject"></div>
209
         </div>
199
         </div>
210
         <div id="settings">
200
         <div id="settings">
211
-          <h1>Connection Settings</h1>
201
+          <h1 data-i18n="connectionsettings"></h1>
212
           <form id="loginInfo">
202
           <form id="loginInfo">
213
             <label>JID: <input id="jid" type="text" name="jid" placeholder="me@example.com"/></label>
203
             <label>JID: <input id="jid" type="text" name="jid" placeholder="me@example.com"/></label>
214
             <label>Password: <input id="password" type="password" name="password" placeholder="secret"/></label>
204
             <label>Password: <input id="password" type="password" name="password" placeholder="secret"/></label>
223
                 <div id="etherpad"></div>
213
                 <div id="etherpad"></div>
224
                 <a target="_new"><div class="watermark leftwatermark"></div></a>
214
                 <a target="_new"><div class="watermark leftwatermark"></div></a>
225
                 <a target="_new"><div class="watermark rightwatermark"></div></a>
215
                 <a target="_new"><div class="watermark rightwatermark"></div></a>
226
-                <a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a>
216
+                <a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
227
                 <div id="activeSpeaker">
217
                 <div id="activeSpeaker">
228
                     <img id="activeSpeakerAvatar" src=""/>
218
                     <img id="activeSpeakerAvatar" src=""/>
229
                     <canvas id="activeSpeakerAudioLevel"></canvas>
219
                     <canvas id="activeSpeakerAudioLevel"></canvas>
238
                     </span>
228
                     </span>
239
                     <audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
229
                     <audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
240
                     <span class="focusindicator"></span>
230
                     <span class="focusindicator"></span>
241
-                    <!--<div class="connectionindicator">
242
-                        <span class="connection connection_empty"><i class="icon-connection"></i></span>
243
-                        <span class="connection connection_full"><i class="icon-connection"></i></span>
244
-                    </div>-->
245
-
246
                 </span>
231
                 </span>
247
                 <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
232
                 <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
248
                 <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
233
                 <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
249
             </div>
234
             </div>
250
             <span id="bottomToolbar">
235
             <span id="bottomToolbar">
251
                 <span class="bottomToolbar_span">
236
                 <span class="bottomToolbar_span">
252
-                    <a class="bottomToolbarButton" id="bottom_toolbar_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" content="Open / close chat">
237
+                    <a class="bottomToolbarButton" id="bottom_toolbar_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" data-i18n="[content]bottomtoolbar.chat" content="Open / close chat">
253
                         <i id="chatBottomButton" class="icon-chat-simple">
238
                         <i id="chatBottomButton" class="icon-chat-simple">
254
                             <span id="bottomUnreadMessages"></span>
239
                             <span id="bottomUnreadMessages"></span>
255
                         </i>
240
                         </i>
257
                 </span>
242
                 </span>
258
                 <div class="bottom_button_separator"></div>
243
                 <div class="bottom_button_separator"></div>
259
                 <span class="bottomToolbar_span">
244
                 <span class="bottomToolbar_span">
260
-                    <a class="bottomToolbarButton" id="bottom_toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover" content="Open / close contact list">
245
+                    <a class="bottomToolbarButton" id="bottom_toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover"  data-i18n="[content]bottomtoolbar.contactlist" content="Open / close contact list">
261
                         <i id="contactListButton" class="icon-contactList">
246
                         <i id="contactListButton" class="icon-contactList">
262
                             <span id="numberOfParticipants"></span>
247
                             <span id="numberOfParticipants"></span>
263
                         </i>
248
                         </i>
265
                 </span>
250
                 </span>
266
                 <div class="bottom_button_separator"></div>
251
                 <div class="bottom_button_separator"></div>
267
                 <span class="bottomToolbar_span">
252
                 <span class="bottomToolbar_span">
268
-                    <a class="bottomToolbarButton" id="bottom_toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" content="Show / hide film strip">
253
+                    <a class="bottomToolbarButton" id="bottom_toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" data-i18n="[content]bottomtoolbar.filmstrip" content="Show / hide film strip">
269
                         <i id="filmStripButton" class="icon-filmstrip"></i>
254
                         <i id="filmStripButton" class="icon-filmstrip"></i>
270
                     </a>
255
                     </a>
271
                 </span>
256
                 </span>
273
         </div>
258
         </div>
274
         <div id="chatspace" class="right-panel">
259
         <div id="chatspace" class="right-panel">
275
             <div id="nickname">
260
             <div id="nickname">
276
-                Enter a nickname in the box below
261
+                <span data-i18n="chat.nickname.title"></span>
277
                 <form>
262
                 <form>
278
-                    <input type='text' id="nickinput" placeholder='Choose a nickname' autofocus>
263
+                    <input type='text' id="nickinput" data-i18n="[placeholder]chat.nickname.popover" autofocus>
279
                 </form>
264
                 </form>
280
             </div>
265
             </div>
281
 
266
 
282
             <!--div><i class="fa fa-comments">&nbsp;</i><span class='nick'></span>:&nbsp;<span class='chattext'></span></div-->
267
             <!--div><i class="fa fa-comments">&nbsp;</i><span class='nick'></span>:&nbsp;<span class='chattext'></span></div-->
283
             <div id="chatconversation"></div>
268
             <div id="chatconversation"></div>
284
             <audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
269
             <audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
285
-                <textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
270
+                <textarea id="usermsg" data-i18n="[placeholder]chat.messagebox" autofocus></textarea>
286
             <div id="smileysarea">
271
             <div id="smileysarea">
287
                 <div id="smileys" id="toggle_smileys">
272
                 <div id="smileys" id="toggle_smileys">
288
                     <img src="images/smile.svg"/>
273
                     <img src="images/smile.svg"/>
291
         </div>
276
         </div>
292
         <div id="contactlist" class="right-panel">
277
         <div id="contactlist" class="right-panel">
293
             <ul>
278
             <ul>
294
-                <li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li>
279
+                <li class="title"><i class="icon-contact-list"></i><span data-i18n="contactlist"></span></li>
295
             </ul>
280
             </ul>
296
         </div>
281
         </div>
297
         <div id="settingsmenu" class="right-panel">
282
         <div id="settingsmenu" class="right-panel">
298
-            <div class="icon-settings"> SETTINGS</div>
283
+            <div class="icon-settings" data-i18n="settings.title"></div>
299
             <img id="avatar" src="https://www.gravatar.com/avatar/87291c37c25be69a072a4514931b1749?d=wavatar&size=30"/>
284
             <img id="avatar" src="https://www.gravatar.com/avatar/87291c37c25be69a072a4514931b1749?d=wavatar&size=30"/>
300
             <div class="arrow-up"></div>
285
             <div class="arrow-up"></div>
301
-            <input type="text" id="setDisplayName" placeholder="Name">
286
+            <input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
302
             <input type="text" id="setEmail" placeholder="E-Mail">
287
             <input type="text" id="setEmail" placeholder="E-Mail">
303
-            <button id="updateSettings">Update</button>
288
+            <button id="updateSettings" data-i18n="settings.update"></button>
304
         </div>
289
         </div>
305
-        <a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
290
+        <a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-i18n="[data-content]downloadlogs" ><i class="fa fa-cloud-download"></i></a>
306
     </div>
291
     </div>
307
   </body>
292
   </body>
308
 </html>
293
 </html>

+ 4
- 0
lang/languages.json View File

1
+{
2
+    "en": "English",
3
+    "bg": "Bulgarian"
4
+}

+ 120
- 0
lang/main.json View File

1
+{
2
+    "contactlist": "CONTACT LIST",
3
+    "connectionsettings": "Connection Settings",
4
+    "poweredby": "powered by",
5
+    "downloadlogs": "Download logs",
6
+    "welcomepage":{
7
+        "go": "GO",
8
+        "roomname": "Enter room name",
9
+        "disable": "Don't show this page next time I enter",
10
+        "feature1": {
11
+            "title": "Simple to use",
12
+            "content": "No downloads required. __app__ works directly within your browser. Simply share your conference URL with others to get started."
13
+        },
14
+        "feature2": {
15
+            "title": "Low bandwidth",
16
+            "content": "Multi-party video conferences work with as little as 128Kbps. Screen-sharing and audio-only conferences are possible with far less."
17
+        },
18
+        "feature3": {
19
+            "title": "Open source",
20
+            "content": "__app__ is licensed under MIT. You are free to download, use, modify, and share them as per these licenses."
21
+        },
22
+        "feature4": {
23
+            "title": "Unlimited users",
24
+            "content": "There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors."
25
+        },
26
+        "feature5": {
27
+            "title": "Screen sharing",
28
+            "content": "It's easy to share your screen with others. __app__ is ideal for on-line presentations, lectures, and tech support sessions."
29
+        },
30
+        "feature6": {
31
+            "title": "Secure rooms",
32
+            "content": "Need some privacy? __app__ conference rooms can be secured with a password in order to exclude unwanted guests and prevent interruptions."
33
+        },
34
+        "feature7": {
35
+            "title": "Shared notes",
36
+            "content": "__app__ features Etherpad, a real-time collaborative text editor that's great for meeting minutes, writing articles, and more."
37
+        },
38
+        "feature8": {
39
+            "title": "Usage statistics",
40
+            "content": "Learn about your users through easy integration with Piwik, Google Analytics, and other usage monitoring and statistics systems."
41
+        }
42
+    },
43
+    "toolbar": {
44
+        "mute": "Mute / Unmute",
45
+        "videomute": "Start / stop camera",
46
+        "authenticate": "Authenticate",
47
+        "record": "Record",
48
+        "lock": "Lock / unlock room",
49
+        "invite": "Invite others",
50
+        "chat": "Open / close chat",
51
+        "prezi": "Share Prezi",
52
+        "etherpad": "Shared document",
53
+        "sharescreen": "Share screen",
54
+        "fullscreen": "Enter / Exit Full Screen",
55
+        "sip": "Call SIP number",
56
+        "Settings": "Settings",
57
+        "hangup": "Hang Up"
58
+    },
59
+    "bottomtoolbar": {
60
+        "chat": "Open / close chat",
61
+        "filmstrip": "Open / close contact list",
62
+        "contactlist": "Show / hide film strip"
63
+    },
64
+    "chat":{
65
+        "nickname": {
66
+            "title": "Enter a nickname in the box below",
67
+            "popover": "Choose a nickname"
68
+        },
69
+        "messagebox": "Enter text..."
70
+    },
71
+    "settings":
72
+    {
73
+        "title": "SETTINGS",
74
+        "update": "Update",
75
+        "name": "Name"
76
+    },
77
+    "videothumbnail":
78
+    {
79
+        "editnickname": "Click to edit your<br/>display name",
80
+        "moderator": "The owner of<br/>this conference",
81
+        "videomute": "Participant has<br/>stopped the camera.",
82
+        "mute": "Participant is muted",
83
+        "kick": "Kick out",
84
+        "muted": "Muted",
85
+        "domute": "Mute"
86
+
87
+    },
88
+    "connectionindicator":
89
+    {
90
+        "bitrate": "Bitrate:",
91
+        "packetloss": "Packet loss: ",
92
+        "resolution": "Resolution:",
93
+        "less": "Show less",
94
+        "more": "Show more",
95
+        "address": "Address:",
96
+        "remoteports": "Remote ports:",
97
+        "localports": "Local ports:",
98
+        "remoteport": "Remote port:",
99
+        "localport": "Local port:",
100
+        "localaddress": "Local address: ",
101
+        "localaddresses": "Local addresses: ",
102
+        "remoteaddress": "Remote address: ",
103
+        "remoteaddresses": "Remote addresses: ",
104
+        "transport": "Transport: ",
105
+        "bandwidth": "Estimated bandwidth:",
106
+        "na": "Come back here for connection information once the conference starts"
107
+    },
108
+    "notify": {
109
+        "disconnected": "disconnected",
110
+        "moderator": "Moderator rights granted !",
111
+        "connected": "connected"
112
+
113
+    }
114
+
115
+
116
+
117
+
118
+
119
+
120
+}

+ 2607
- 298
libs/app.bundle.js
File diff suppressed because it is too large
View File


+ 1
- 9
modules/UI/UI.js View File

340
         "newestOnTop": false
340
         "newestOnTop": false
341
     };
341
     };
342
 
342
 
343
-    $('#settingsmenu>input').keyup(function(event){
344
-        if(event.keyCode === 13) {//enter
345
-            SettingsMenu.update();
346
-        }
347
-    });
348
-
349
-    $("#updateSettings").click(function () {
350
-        SettingsMenu.update();
351
-    });
343
+    SettingsMenu.init();
352
 
344
 
353
 };
345
 };
354
 
346
 

+ 34
- 0
modules/UI/side_pannels/settings/SettingsMenu.js View File

1
 var Avatar = require("../../avatar/Avatar");
1
 var Avatar = require("../../avatar/Avatar");
2
 var Settings = require("./Settings");
2
 var Settings = require("./Settings");
3
 var UIUtil = require("../../util/UIUtil");
3
 var UIUtil = require("../../util/UIUtil");
4
+var languages = require("../../../../service/translation/languages");
5
+
6
+function generateLanguagesSelectBox()
7
+{
8
+    var currentLang = APP.translation.getCurrentLanguage();
9
+    var html = "<select id=\"languages_selectbox\">";
10
+    var langArray = languages.getLanguages();
11
+    for(var i = 0; i < langArray.length; i++)
12
+    {
13
+        var lang = langArray[i];
14
+        html += "<option ";
15
+        if(lang === currentLang)
16
+            html += "selected ";
17
+        html += "value=\"" + lang + "\" data-i18n='languages:" + lang + "'>";
18
+        html += "</option>";
19
+
20
+    }
21
+
22
+    return html + "</select>";
23
+}
4
 
24
 
5
 
25
 
6
 var SettingsMenu = {
26
 var SettingsMenu = {
7
 
27
 
28
+    init: function () {
29
+        $("#updateSettings").before(generateLanguagesSelectBox());
30
+        $('#settingsmenu>input').keyup(function(event){
31
+            if(event.keyCode === 13) {//enter
32
+                SettingsMenu.update();
33
+            }
34
+        });
35
+
36
+        $("#updateSettings").click(function () {
37
+            SettingsMenu.update();
38
+        });
39
+    },
40
+
8
     update: function() {
41
     update: function() {
9
         var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
42
         var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
10
         var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
43
         var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
14
             APP.xmpp.addToPresence("displayName", displayName, true);
47
             APP.xmpp.addToPresence("displayName", displayName, true);
15
         }
48
         }
16
 
49
 
50
+        APP.translation.setLanguage($("#languages_selectbox").val());
17
 
51
 
18
         APP.xmpp.addToPresence("email", newEmail);
52
         APP.xmpp.addToPresence("email", newEmail);
19
         var email = Settings.setEmail(newEmail);
53
         var email = Settings.setEmail(newEmail);

+ 2
- 2
modules/UI/util/UIUtil.js View File

69
         context.putImageData(imgData, 0, 0);
69
         context.putImageData(imgData, 0, 0);
70
     },
70
     },
71
 
71
 
72
-    setTooltip: function (element, tooltipText, position) {
73
-        element.setAttribute("data-content", tooltipText);
72
+    setTooltip: function (element, key, position) {
73
+        element.setAttribute("data-i18n", "[data-content]" + key);
74
         element.setAttribute("data-toggle", "popover");
74
         element.setAttribute("data-toggle", "popover");
75
         element.setAttribute("data-placement", position);
75
         element.setAttribute("data-placement", position);
76
         element.setAttribute("data-html", true);
76
         element.setAttribute("data-html", true);

+ 55
- 34
modules/UI/videolayout/ConnectionIndicator.js View File

64
 ConnectionIndicator.prototype.generateText = function () {
64
 ConnectionIndicator.prototype.generateText = function () {
65
     var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
65
     var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
66
 
66
 
67
+    var translate = APP.translation.translateString;
68
+
67
     if(this.bitrate === null)
69
     if(this.bitrate === null)
68
     {
70
     {
69
         downloadBitrate = "N/A";
71
         downloadBitrate = "N/A";
145
 
147
 
146
     var result = "<table style='width:100%'>" +
148
     var result = "<table style='width:100%'>" +
147
         "<tr>" +
149
         "<tr>" +
148
-        "<td><span class='jitsipopover_blue'>Bitrate:</span></td>" +
150
+        "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.bitrate'>" +
151
+        translate("connectionindicator.bitrate") + "</span></td>" +
149
         "<td><span class='jitsipopover_green'>&darr;</span>" +
152
         "<td><span class='jitsipopover_green'>&darr;</span>" +
150
         downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
153
         downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
151
         uploadBitrate + "</td>" +
154
         uploadBitrate + "</td>" +
152
         "</tr><tr>" +
155
         "</tr><tr>" +
153
-        "<td><span class='jitsipopover_blue'>Packet loss: </span></td>" +
156
+        "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.packetloss'>" +
157
+        translate("connectionindicator.packetloss") + "</span></td>" +
154
         "<td>" + packetLoss  + "</td>" +
158
         "<td>" + packetLoss  + "</td>" +
155
         "</tr><tr>" +
159
         "</tr><tr>" +
156
-        "<td><span class='jitsipopover_blue'>Resolution:</span></td>" +
160
+        "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.resolution'>" +
161
+        translate("connectionindicator.resolution") + "</span></td>" +
157
         "<td>" + resolution + "</td></tr></table>";
162
         "<td>" + resolution + "</td></tr></table>";
158
 
163
 
159
-    if(this.videoContainer.id == "localVideoContainer")
164
+    if(this.videoContainer.id == "localVideoContainer") {
160
         result += "<div class=\"jitsipopover_showmore\" " +
165
         result += "<div class=\"jitsipopover_showmore\" " +
161
             "onclick = \"APP.UI.connectionIndicatorShowMore('" +
166
             "onclick = \"APP.UI.connectionIndicatorShowMore('" +
162
-            this.videoContainer.id + "')\">" +
163
-            (this.showMoreValue? "Show less" : "Show More") + "</div><br />";
167
+            this.videoContainer.id + "')\"  data-i18n='connectionindicator." +
168
+                (this.showMoreValue ? "less" : "more") + "'>" +
169
+            translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
170
+            "</div><br />";
171
+    }
164
 
172
 
165
     if(this.showMoreValue)
173
     if(this.showMoreValue)
166
     {
174
     {
183
         if(!this.transport || this.transport.length === 0)
191
         if(!this.transport || this.transport.length === 0)
184
         {
192
         {
185
             transport = "<tr>" +
193
             transport = "<tr>" +
186
-                "<td><span class='jitsipopover_blue'>Address:</span></td>" +
194
+                "<td><span class='jitsipopover_blue' " +
195
+                "data-i18n='connectionindicator.address'>" +
196
+                translate("connectionindicator.address") + "</span></td>" +
187
                 "<td> N/A</td></tr>";
197
                 "<td> N/A</td></tr>";
188
         }
198
         }
189
         else
199
         else
218
                 }
228
                 }
219
 
229
 
220
             }
230
             }
231
+
232
+            var local_address_key = "connectionindicator." +
233
+                (data.localIP.length > 1? "localaddresses" : "localaddress");
234
+            var remote_address_key = "connectionindicator." +
235
+                (data.remoteIP.length > 1? "remoteaddresses" : "remoteaddress");
221
             var localTransport =
236
             var localTransport =
222
-                "<tr><td><span class='jitsipopover_blue'>Local address" +
223
-                (data.localIP.length > 1? "es" : "") + ": </span></td><td> " +
237
+                "<tr><td><span class='jitsipopover_blue' data-i18n='" +
238
+                local_address_key +"'>" +
239
+                    translate(local_address_key) + "</span></td><td> " +
224
                 ConnectionIndicator.getStringFromArray(data.localIP) +
240
                 ConnectionIndicator.getStringFromArray(data.localIP) +
225
                 "</td></tr>";
241
                 "</td></tr>";
226
             transport =
242
             transport =
227
-                "<tr><td><span class='jitsipopover_blue'>Remote address"+
228
-                (data.remoteIP.length > 1? "es" : "") + ":</span></td><td> " +
243
+                "<tr><td><span class='jitsipopover_blue' data-i18n='" +
244
+                remote_address_key + "'>" +
245
+                    translate(remote_address_key) + "</span></td><td> " +
229
                 ConnectionIndicator.getStringFromArray(data.remoteIP) +
246
                 ConnectionIndicator.getStringFromArray(data.remoteIP) +
230
                 "</td></tr>";
247
                 "</td></tr>";
248
+
249
+            var key_remote = "connectionindicator.",
250
+                key_local = "connectionindicator.";
251
+
231
             if(this.transport.length > 1)
252
             if(this.transport.length > 1)
232
             {
253
             {
233
-                transport += "<tr>" +
234
-                    "<td>" +
235
-                    "<span class='jitsipopover_blue'>Remote ports:</span>" +
236
-                    "</td><td>";
237
-                localTransport += "<tr>" +
238
-                    "<td>" +
239
-                    "<span class='jitsipopover_blue'>Local ports:</span>" +
240
-                    "</td><td>";
254
+                key_remote += "remoteports";
255
+                key_local += "localports";
241
             }
256
             }
242
             else
257
             else
243
             {
258
             {
244
-                transport +=
245
-                    "<tr>" +
246
-                    "<td>" +
247
-                    "<span class='jitsipopover_blue'>Remote port:</span>" +
248
-                    "</td><td>";
249
-                localTransport +=
250
-                    "<tr>" +
251
-                    "<td>" +
252
-                    "<span class='jitsipopover_blue'>Local port:</span>" +
253
-                    "</td><td>";
259
+                key_remote += "remoteport";
260
+                key_local += "localport";
254
             }
261
             }
255
 
262
 
263
+            transport += "<tr>" +
264
+                "<td>" +
265
+                "<span class='jitsipopover_blue' data-i18n='" + key_remote +
266
+                "'>" +
267
+                translate(key_remote) + "</span></td><td>";
268
+            localTransport += "<tr>" +
269
+                "<td>" +
270
+                "<span class='jitsipopover_blue' data-i18n='" + key_local +
271
+                "'>" +
272
+                translate(key_local) + "</span></td><td>";
273
+
256
             transport +=
274
             transport +=
257
                 ConnectionIndicator.getStringFromArray(data.remotePort);
275
                 ConnectionIndicator.getStringFromArray(data.remotePort);
258
             localTransport +=
276
             localTransport +=
260
             transport += "</td></tr>";
278
             transport += "</td></tr>";
261
             transport += localTransport + "</td></tr>";
279
             transport += localTransport + "</td></tr>";
262
             transport +="<tr>" +
280
             transport +="<tr>" +
263
-                "<td><span class='jitsipopover_blue'>Transport:</span></td>" +
281
+                "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.transport'>" +
282
+                translate("connectionindicator.transport") + "</span></td>" +
264
                 "<td>" + this.transport[0].type + "</td></tr>";
283
                 "<td>" + this.transport[0].type + "</td></tr>";
265
 
284
 
266
         }
285
         }
268
         result += "<table  style='width:100%'>" +
287
         result += "<table  style='width:100%'>" +
269
             "<tr>" +
288
             "<tr>" +
270
             "<td>" +
289
             "<td>" +
271
-            "<span class='jitsipopover_blue'>Estimated bandwidth:</span>" +
290
+            "<span class='jitsipopover_blue' data-i18n='connectionindicator.bandwidth'>" +
291
+            translate("connectionindicator.bandwidth") + "</span>" +
272
             "</td><td>" +
292
             "</td><td>" +
273
             "<span class='jitsipopover_green'>&darr;</span>" +
293
             "<span class='jitsipopover_green'>&darr;</span>" +
274
             downloadBandwidth +
294
             downloadBandwidth +
313
     this.videoContainer.appendChild(this.connectionIndicatorContainer);
333
     this.videoContainer.appendChild(this.connectionIndicatorContainer);
314
     this.popover = new JitsiPopover(
334
     this.popover = new JitsiPopover(
315
         $("#" + this.videoContainer.id + " > .connectionindicator"),
335
         $("#" + this.videoContainer.id + " > .connectionindicator"),
316
-        {content: "<div class=\"connection_info\">Come back here for " +
317
-            "connection information once the conference starts</div>",
336
+        {content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
337
+            APP.translation.translateString("connectionindicator.na") + "</div>",
318
             skin: "black"});
338
             skin: "black"});
319
 
339
 
320
     this.emptyIcon = this.connectionIndicatorContainer.appendChild(
340
     this.emptyIcon = this.connectionIndicatorContainer.appendChild(
388
  */
408
  */
389
 ConnectionIndicator.prototype.updatePopoverData = function () {
409
 ConnectionIndicator.prototype.updatePopoverData = function () {
390
     this.popover.updateContent(
410
     this.popover.updateContent(
391
-            "<div class=\"connection_info\">" + this.generateText() + "</div>");
411
+        "<div class=\"connection_info\">" + this.generateText() + "</div>");
412
+    APP.translation.translateElement($(".connection_info"));
392
 };
413
 };
393
 
414
 
394
 /**
415
 /**

+ 27
- 14
modules/UI/videolayout/VideoLayout.js View File

235
         } else {
235
         } else {
236
             nameSpan.id = 'localDisplayName';
236
             nameSpan.id = 'localDisplayName';
237
             $('#' + videoSpanId)[0].appendChild(editButton);
237
             $('#' + videoSpanId)[0].appendChild(editButton);
238
+            //translates popover of edit button
239
+            APP.translation.translateElement($("a.displayname"));
238
 
240
 
239
             var editableText = document.createElement('input');
241
             var editableText = document.createElement('input');
240
             editableText.className = 'displayname';
242
             editableText.className = 'displayname';
345
     var muteMenuItem = document.createElement('li');
347
     var muteMenuItem = document.createElement('li');
346
     var muteLinkItem = document.createElement('a');
348
     var muteLinkItem = document.createElement('a');
347
 
349
 
348
-    var mutedIndicator = "<i class='icon-mic-disabled'></i>";
350
+    var mutedIndicator = "<i style='float:left;' class='icon-mic-disabled'></i>";
349
 
351
 
350
     if (!mutedAudios[jid]) {
352
     if (!mutedAudios[jid]) {
351
-        muteLinkItem.innerHTML = mutedIndicator + 'Mute';
353
+        muteLinkItem.innerHTML = mutedIndicator +
354
+            " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
352
         muteLinkItem.className = 'mutelink';
355
         muteLinkItem.className = 'mutelink';
353
     }
356
     }
354
     else {
357
     else {
355
-        muteLinkItem.innerHTML = mutedIndicator + ' Muted';
358
+        muteLinkItem.innerHTML = mutedIndicator +
359
+            " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
356
         muteLinkItem.className = 'mutelink disabled';
360
         muteLinkItem.className = 'mutelink disabled';
357
     }
361
     }
358
 
362
 
366
         popupmenuElement.setAttribute('style', 'display:none;');
370
         popupmenuElement.setAttribute('style', 'display:none;');
367
 
371
 
368
         if (isMute) {
372
         if (isMute) {
369
-            this.innerHTML = mutedIndicator + ' Muted';
373
+            this.innerHTML = mutedIndicator +
374
+                " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
370
             this.className = 'mutelink disabled';
375
             this.className = 'mutelink disabled';
371
         }
376
         }
372
         else {
377
         else {
373
-            this.innerHTML = mutedIndicator + ' Mute';
378
+            this.innerHTML = mutedIndicator +
379
+                " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
374
             this.className = 'mutelink';
380
             this.className = 'mutelink';
375
         }
381
         }
376
     };
382
     };
378
     muteMenuItem.appendChild(muteLinkItem);
384
     muteMenuItem.appendChild(muteLinkItem);
379
     popupmenuElement.appendChild(muteMenuItem);
385
     popupmenuElement.appendChild(muteMenuItem);
380
 
386
 
381
-    var ejectIndicator = "<i class='fa fa-eject'></i>";
387
+    var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
382
 
388
 
383
     var ejectMenuItem = document.createElement('li');
389
     var ejectMenuItem = document.createElement('li');
384
     var ejectLinkItem = document.createElement('a');
390
     var ejectLinkItem = document.createElement('a');
385
-    ejectLinkItem.innerHTML = ejectIndicator + ' Kick out';
391
+    var ejectText = "<div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.kick'>&nbsp;</div>";
392
+    ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
386
     ejectLinkItem.onclick = function(){
393
     ejectLinkItem.onclick = function(){
387
         APP.xmpp.eject(jid);
394
         APP.xmpp.eject(jid);
388
         popupmenuElement.setAttribute('style', 'display:none;');
395
         popupmenuElement.setAttribute('style', 'display:none;');
394
     var paddingSpan = document.createElement('span');
401
     var paddingSpan = document.createElement('span');
395
     paddingSpan.className = 'popupmenuPadding';
402
     paddingSpan.className = 'popupmenuPadding';
396
     popupmenuElement.appendChild(paddingSpan);
403
     popupmenuElement.appendChild(paddingSpan);
404
+    APP.translation.translateElement($("#" + popupmenuElement.id + " > li > a > div"));
397
 }
405
 }
398
 
406
 
399
 /**
407
 /**
468
     var editButton = document.createElement('a');
476
     var editButton = document.createElement('a');
469
     editButton.className = 'displayname';
477
     editButton.className = 'displayname';
470
     UIUtil.setTooltip(editButton,
478
     UIUtil.setTooltip(editButton,
471
-        'Click to edit your<br/>display name',
479
+        "videothumbnail.editnickname",
472
         "top");
480
         "top");
473
     editButton.innerHTML = '<i class="fa fa-pencil"></i>';
481
     editButton.innerHTML = '<i class="fa fa-pencil"></i>';
474
 
482
 
487
     parentElement.appendChild(moderatorIndicator);
495
     parentElement.appendChild(moderatorIndicator);
488
 
496
 
489
     UIUtil.setTooltip(parentElement,
497
     UIUtil.setTooltip(parentElement,
490
-        "The owner of<br/>this conference",
498
+        "videothumbnail.moderator",
491
         "top");
499
         "top");
492
 }
500
 }
493
 
501
 
1043
         container.id = spanId;
1051
         container.id = spanId;
1044
         container.className = 'videocontainer';
1052
         container.className = 'videocontainer';
1045
         var remotes = document.getElementById('remoteVideos');
1053
         var remotes = document.getElementById('remoteVideos');
1046
-
1054
+        remotes.appendChild(container);
1047
         // If the peerJid is null then this video span couldn't be directly
1055
         // If the peerJid is null then this video span couldn't be directly
1048
         // associated with a participant (this could happen in the case of prezi).
1056
         // associated with a participant (this could happen in the case of prezi).
1049
         if (APP.xmpp.isModerator() && peerJid !== null)
1057
         if (APP.xmpp.isModerator() && peerJid !== null)
1050
             addRemoteVideoMenu(peerJid, container);
1058
             addRemoteVideoMenu(peerJid, container);
1051
-
1052
-        remotes.appendChild(container);
1053
         AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
1059
         AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
1054
 
1060
 
1055
         return container;
1061
         return container;
1335
             if (indicatorSpan.children().length === 0)
1341
             if (indicatorSpan.children().length === 0)
1336
             {
1342
             {
1337
                 createModeratorIndicatorElement(indicatorSpan[0]);
1343
                 createModeratorIndicatorElement(indicatorSpan[0]);
1344
+                //translates text in focus indicator
1345
+                APP.translation.translateElement($('#localVideoContainer .focusindicator'));
1338
             }
1346
             }
1339
         }
1347
         }
1340
 
1348
 
1375
                     videoContainer.appendChild(indicatorSpan);
1383
                     videoContainer.appendChild(indicatorSpan);
1376
 
1384
 
1377
                     createModeratorIndicatorElement(indicatorSpan);
1385
                     createModeratorIndicatorElement(indicatorSpan);
1386
+                    //translates text in focus indicators
1387
+                    APP.translation.translateElement($('#' + videoSpanId + ' .focusindicator'));
1378
                 }
1388
                 }
1379
             } else if (isModerator) {
1389
             } else if (isModerator) {
1380
                 // We are moderator, but user is not - add menu
1390
                 // We are moderator, but user is not - add menu
1408
                 var mutedIndicator = document.createElement('i');
1418
                 var mutedIndicator = document.createElement('i');
1409
                 mutedIndicator.className = 'icon-camera-disabled';
1419
                 mutedIndicator.className = 'icon-camera-disabled';
1410
                 UIUtil.setTooltip(mutedIndicator,
1420
                 UIUtil.setTooltip(mutedIndicator,
1411
-                    "Participant has<br/>stopped the camera.",
1421
+                    "videothumbnail.videomute",
1412
                     "top");
1422
                     "top");
1413
                 videoMutedSpan.appendChild(mutedIndicator);
1423
                 videoMutedSpan.appendChild(mutedIndicator);
1424
+                //translate texts for muted indicator
1425
+                APP.translation.translateElement($('#' + videoSpanId  + " > i"));
1414
             }
1426
             }
1415
 
1427
 
1416
             VideoLayout.updateMutePosition(videoSpanId);
1428
             VideoLayout.updateMutePosition(videoSpanId);
1451
                 audioMutedSpan = document.createElement('span');
1463
                 audioMutedSpan = document.createElement('span');
1452
                 audioMutedSpan.className = 'audioMuted';
1464
                 audioMutedSpan.className = 'audioMuted';
1453
                 UIUtil.setTooltip(audioMutedSpan,
1465
                 UIUtil.setTooltip(audioMutedSpan,
1454
-                    "Participant is muted",
1466
+                    "videothumbnail.mute",
1455
                     "top");
1467
                     "top");
1456
 
1468
 
1457
                 $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
1469
                 $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
1470
+                APP.translation.translateElement($('#' + videoSpanId + " > span"));
1458
                 var mutedIndicator = document.createElement('i');
1471
                 var mutedIndicator = document.createElement('i');
1459
                 mutedIndicator.className = 'icon-mic-disabled';
1472
                 mutedIndicator.className = 'icon-mic-disabled';
1460
                 audioMutedSpan.appendChild(mutedIndicator);
1473
                 audioMutedSpan.appendChild(mutedIndicator);

+ 0
- 2
modules/UI/welcome_page/WelcomePage.js View File

37
     $("#videoconference_page").hide();
37
     $("#videoconference_page").hide();
38
     $("#domain_name").text(
38
     $("#domain_name").text(
39
             window.location.protocol + "//" + window.location.host + "/");
39
             window.location.protocol + "//" + window.location.host + "/");
40
-    $("span[name='appName']").text(interfaceConfig.APP_NAME);
41
-
42
     if (interfaceConfig.SHOW_JITSI_WATERMARK) {
40
     if (interfaceConfig.SHOW_JITSI_WATERMARK) {
43
         var leftWatermarkDiv
41
         var leftWatermarkDiv
44
             = $("#welcome_page_header div[class='watermark leftwatermark']");
42
             = $("#welcome_page_header div[class='watermark leftwatermark']");

+ 110
- 0
modules/translation/translation.js View File

1
+var i18n = require("i18next-client");
2
+var languages = require("../../service/translation/languages");
3
+var DEFAULT_LANG = languages.EN;
4
+var initialized = false;
5
+var waitingForInit = [];
6
+
7
+i18n.addPostProcessor("resolveAppName", function(value, key, options) {
8
+    return value.replace("__app__", interfaceConfig.APP_NAME);
9
+});
10
+
11
+
12
+
13
+var defaultOptions = {
14
+    detectLngQS: "lang",
15
+    useCookie: false,
16
+    fallbackLng: DEFAULT_LANG,
17
+    load: "unspecific",
18
+    resGetPath: 'lang/__ns__-__lng__.json',
19
+    ns: {
20
+        namespaces: ['main', 'languages'],
21
+        defaultNs: 'main'
22
+    },
23
+    lngWhitelist : languages.getLanguages(),
24
+    fallbackOnNull: true,
25
+    useDataAttrOptions: true,
26
+    app: interfaceConfig.APP_NAME,
27
+    getAsync: true,
28
+    customLoad: function(lng, ns, options, done) {
29
+        var resPath = "lang/__ns__-__lng__.json";
30
+        if(lng === languages.EN)
31
+            resPath = "lang/__ns__.json";
32
+        var url = i18n.functions.applyReplacement(resPath, { lng: lng, ns: ns });
33
+        initialized = false;
34
+        i18n.functions.ajax({
35
+            url: url,
36
+            success: function(data, status, xhr) {
37
+                i18n.functions.log('loaded: ' + url);
38
+                done(null, data);
39
+            },
40
+            error : function(xhr, status, error) {
41
+                if ((status && status == 200) ||
42
+                    (xhr && xhr.status && xhr.status == 200)) {
43
+                    // file loaded but invalid json, stop waste time !
44
+                    i18n.functions.error('There is a typo in: ' + url);
45
+                } else if ((status && status == 404) ||
46
+                    (xhr && xhr.status && xhr.status == 404)) {
47
+                    i18n.functions.log('Does not exist: ' + url);
48
+                } else {
49
+                    var theStatus = status ? status :
50
+                        ((xhr && xhr.status) ? xhr.status : null);
51
+                    i18n.functions.log(theStatus + ' when loading ' + url);
52
+                }
53
+
54
+                done(error, {});
55
+            },
56
+            dataType: "json",
57
+            async : options.getAsync
58
+        });
59
+    }
60
+    //              options for caching
61
+//                useLocalStorage: true,
62
+//                localStorageExpirationTime: 86400000 // in ms, default 1 week
63
+};
64
+
65
+function initCompleted(t)
66
+{
67
+    initialized = true;
68
+    $("[data-i18n]").i18n();
69
+    for(var i = 0; i < waitingForInit.length; i++)
70
+    {
71
+        var obj = waitingForInit[i];
72
+        obj.callback(i18n.t(obj.key));
73
+    }
74
+    waitingForInit = [];
75
+}
76
+
77
+module.exports = {
78
+    init: function (lang) {
79
+        initialized = false;
80
+        var options = defaultOptions;
81
+        if(lang)
82
+            options.lng = lang;
83
+        i18n.init(options, initCompleted);
84
+    },
85
+    translateString: function (key, cb) {
86
+        if(!cb)
87
+            return i18n.t(key);
88
+
89
+        if(initialized)
90
+        {
91
+            cb(i18n.t(key));
92
+        }
93
+        else
94
+        {
95
+            waitingForInit.push({"callback": cb, "key": key});
96
+        }
97
+    },
98
+    setLanguage: function (lang) {
99
+        initialized = false;
100
+        if(!lang)
101
+            lang = DEFAULT_LANG;
102
+        i18n.setLng(lang, defaultOptions, initCompleted);
103
+    },
104
+    getCurrentLanguage: function () {
105
+        return i18n.lng();
106
+    },
107
+    translateElement: function (selector) {
108
+        selector.i18n();
109
+    }
110
+};

+ 2
- 1
package.json View File

16
   "readmeFilename": "README.md",
16
   "readmeFilename": "README.md",
17
   "dependencies": {
17
   "dependencies": {
18
       "events": "*",
18
       "events": "*",
19
-      "pako": "*"
19
+      "pako": "*",
20
+      "i18next-client": "*"
20
   },
21
   },
21
   "devDependencies": {
22
   "devDependencies": {
22
   },
23
   },

+ 12
- 0
service/translation/languages.js View File

1
+module.exports = {
2
+    getLanguages : function () {
3
+        var languages = [];
4
+        for(var lang in this)
5
+        {
6
+            if(typeof this[lang] === "string")
7
+                languages.push(this[lang]);
8
+        }
9
+        return languages;
10
+    },
11
+    EN: "en"
12
+}

Loading…
Cancel
Save