]>
git.proxmox.com Git - mirror_novnc.git/blob - app/localization.js
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2018 The noVNC Authors
4 * Licensed under MPL 2.0 (see LICENSE.txt)
6 * See README.md for usage and integration instructions.
10 * Localization Utilities
13 export class Localizer
{
15 // Currently configured language
18 // Current dictionary of translations
19 this.dictionary
= undefined;
22 // Configure suitable language based on user preferences
23 setup(supportedLanguages
) {
24 this.language
= 'en'; // Default: US English
27 * Navigator.languages only available in Chrome (32+) and FireFox (32+)
28 * Fall back to navigator.language for other browsers
31 if (typeof window
.navigator
.languages
== 'object') {
32 userLanguages
= window
.navigator
.languages
;
34 userLanguages
= [navigator
.language
|| navigator
.userLanguage
];
37 for (let i
= 0;i
< userLanguages
.length
;i
++) {
38 const userLang
= userLanguages
[i
]
44 if ((userLang
[0] === 'en') &&
45 ((userLang
[1] === undefined) || (userLang
[1] === 'us'))) {
49 // First pass: perfect match
50 for (let j
= 0; j
< supportedLanguages
.length
; j
++) {
51 const supLang
= supportedLanguages
[j
]
56 if (userLang
[0] !== supLang
[0]) {
59 if (userLang
[1] !== supLang
[1]) {
63 this.language
= supportedLanguages
[j
];
67 // Second pass: fallback
68 for (let j
= 0;j
< supportedLanguages
.length
;j
++) {
69 const supLang
= supportedLanguages
[j
]
74 if (userLang
[0] !== supLang
[0]) {
77 if (supLang
[1] !== undefined) {
81 this.language
= supportedLanguages
[j
];
87 // Retrieve localised text
89 if (typeof this.dictionary
!== 'undefined' && this.dictionary
[id
]) {
90 return this.dictionary
[id
];
96 // Traverses the DOM and translates relevant fields
97 // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
101 function process(elem
, enabled
) {
102 function isAnyOf(searchElement
, items
) {
103 return items
.indexOf(searchElement
) !== -1;
106 function translateAttribute(elem
, attr
) {
107 const str
= self
.get(elem
.getAttribute(attr
));
108 elem
.setAttribute(attr
, str
);
111 function translateTextNode(node
) {
112 const str
= self
.get(node
.data
.trim());
116 if (elem
.hasAttribute("translate")) {
117 if (isAnyOf(elem
.getAttribute("translate"), ["", "yes"])) {
119 } else if (isAnyOf(elem
.getAttribute("translate"), ["no"])) {
125 if (elem
.hasAttribute("abbr") &&
126 elem
.tagName
=== "TH") {
127 translateAttribute(elem
, "abbr");
129 if (elem
.hasAttribute("alt") &&
130 isAnyOf(elem
.tagName
, ["AREA", "IMG", "INPUT"])) {
131 translateAttribute(elem
, "alt");
133 if (elem
.hasAttribute("download") &&
134 isAnyOf(elem
.tagName
, ["A", "AREA"])) {
135 translateAttribute(elem
, "download");
137 if (elem
.hasAttribute("label") &&
138 isAnyOf(elem
.tagName
, ["MENUITEM", "MENU", "OPTGROUP",
139 "OPTION", "TRACK"])) {
140 translateAttribute(elem
, "label");
142 // FIXME: Should update "lang"
143 if (elem
.hasAttribute("placeholder") &&
144 isAnyOf(elem
.tagName
, ["INPUT", "TEXTAREA"])) {
145 translateAttribute(elem
, "placeholder");
147 if (elem
.hasAttribute("title")) {
148 translateAttribute(elem
, "title");
150 if (elem
.hasAttribute("value") &&
151 elem
.tagName
=== "INPUT" &&
152 isAnyOf(elem
.getAttribute("type"), ["reset", "button", "submit"])) {
153 translateAttribute(elem
, "value");
157 for (let i
= 0; i
< elem
.childNodes
.length
; i
++) {
158 const node
= elem
.childNodes
[i
];
159 if (node
.nodeType
=== node
.ELEMENT_NODE
) {
160 process(node
, enabled
);
161 } else if (node
.nodeType
=== node
.TEXT_NODE
&& enabled
) {
162 translateTextNode(node
);
167 process(document
.body
, true);
171 export const l10n
= new Localizer();
172 export default l10n
.get.bind(l10n
);