]>
git.proxmox.com Git - mirror_novnc.git/blob - core/util/localization.js
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2012 Joel Martin
4 * Licensed under MPL 2.0 (see LICENSE.txt)
6 * See README.md for usage and integration instructions.
10 * Localization Utilities
13 export function Localizer() {
14 // Currently configured language
17 // Current dictionary of translations
18 this.dictionary
= undefined;
21 Localizer
.prototype = {
22 // Configure suitable language based on user preferences
23 setup: function (supportedLanguages
) {
26 this.language
= 'en'; // Default: US English
29 * Navigator.languages only available in Chrome (32+) and FireFox (32+)
30 * Fall back to navigator.language for other browsers
32 if (typeof window
.navigator
.languages
== 'object') {
33 userLanguages
= window
.navigator
.languages
;
35 userLanguages
= [navigator
.language
|| navigator
.userLanguage
];
38 for (var i
= 0;i
< userLanguages
.length
;i
++) {
39 var userLang
= userLanguages
[i
];
40 userLang
= userLang
.toLowerCase();
41 userLang
= userLang
.replace("_", "-");
42 userLang
= userLang
.split("-");
45 if ((userLang
[0] === 'en') &&
46 ((userLang
[1] === undefined) || (userLang
[1] === 'us'))) {
50 // First pass: perfect match
51 for (var j
= 0;j
< supportedLanguages
.length
;j
++) {
52 var supLang
= supportedLanguages
[j
];
53 supLang
= supLang
.toLowerCase();
54 supLang
= supLang
.replace("_", "-");
55 supLang
= supLang
.split("-");
57 if (userLang
[0] !== supLang
[0])
59 if (userLang
[1] !== supLang
[1])
62 this.language
= supportedLanguages
[j
];
66 // Second pass: fallback
67 for (var j
= 0;j
< supportedLanguages
.length
;j
++) {
68 supLang
= supportedLanguages
[j
];
69 supLang
= supLang
.toLowerCase();
70 supLang
= supLang
.replace("_", "-");
71 supLang
= supLang
.split("-");
73 if (userLang
[0] !== supLang
[0])
75 if (supLang
[1] !== undefined)
78 this.language
= supportedLanguages
[j
];
84 // Retrieve localised text
86 if (typeof this.dictionary
!== 'undefined' && this.dictionary
[id
]) {
87 return this.dictionary
[id
];
93 // Traverses the DOM and translates relevant fields
94 // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
95 translateDOM: function () {
97 function process(elem
, enabled
) {
98 function isAnyOf(searchElement
, items
) {
99 return items
.indexOf(searchElement
) !== -1;
102 function translateAttribute(elem
, attr
) {
103 var str
= elem
.getAttribute(attr
);
105 elem
.setAttribute(attr
, str
);
108 function translateTextNode(node
) {
109 var str
= node
.data
.trim();
114 if (elem
.hasAttribute("translate")) {
115 if (isAnyOf(elem
.getAttribute("translate"), ["", "yes"])) {
117 } else if (isAnyOf(elem
.getAttribute("translate"), ["no"])) {
123 if (elem
.hasAttribute("abbr") &&
124 elem
.tagName
=== "TH") {
125 translateAttribute(elem
, "abbr");
127 if (elem
.hasAttribute("alt") &&
128 isAnyOf(elem
.tagName
, ["AREA", "IMG", "INPUT"])) {
129 translateAttribute(elem
, "alt");
131 if (elem
.hasAttribute("download") &&
132 isAnyOf(elem
.tagName
, ["A", "AREA"])) {
133 translateAttribute(elem
, "download");
135 if (elem
.hasAttribute("label") &&
136 isAnyOf(elem
.tagName
, ["MENUITEM", "MENU", "OPTGROUP",
137 "OPTION", "TRACK"])) {
138 translateAttribute(elem
, "label");
140 // FIXME: Should update "lang"
141 if (elem
.hasAttribute("placeholder") &&
142 isAnyOf(elem
.tagName
, ["INPUT", "TEXTAREA"])) {
143 translateAttribute(elem
, "placeholder");
145 if (elem
.hasAttribute("title")) {
146 translateAttribute(elem
, "title");
148 if (elem
.hasAttribute("value") &&
149 elem
.tagName
=== "INPUT" &&
150 isAnyOf(elem
.getAttribute("type"), ["reset", "button"])) {
151 translateAttribute(elem
, "value");
155 for (var i
= 0;i
< elem
.childNodes
.length
;i
++) {
156 let node
= elem
.childNodes
[i
];
157 if (node
.nodeType
=== node
.ELEMENT_NODE
) {
158 process(node
, enabled
);
159 } else if (node
.nodeType
=== node
.TEXT_NODE
&& enabled
) {
160 translateTextNode(node
);
165 process(document
.body
, true);
169 export const l10n
= new Localizer();
170 export default l10n
.get.bind(l10n
);