]>
git.proxmox.com Git - mirror_novnc.git/blob - app/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 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])
58 if (userLang
[1] !== supLang
[1])
61 this.language
= supportedLanguages
[j
];
65 // Second pass: fallback
66 for (let j
= 0;j
< supportedLanguages
.length
;j
++) {
67 const supLang
= supportedLanguages
[j
]
72 if (userLang
[0] !== supLang
[0])
74 if (supLang
[1] !== undefined)
77 this.language
= supportedLanguages
[j
];
83 // Retrieve localised text
85 if (typeof this.dictionary
!== 'undefined' && this.dictionary
[id
]) {
86 return this.dictionary
[id
];
92 // Traverses the DOM and translates relevant fields
93 // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
97 function process(elem
, enabled
) {
98 function isAnyOf(searchElement
, items
) {
99 return items
.indexOf(searchElement
) !== -1;
102 function translateAttribute(elem
, attr
) {
103 const str
= self
.get(elem
.getAttribute(attr
));
104 elem
.setAttribute(attr
, str
);
107 function translateTextNode(node
) {
108 const str
= self
.get(node
.data
.trim());
112 if (elem
.hasAttribute("translate")) {
113 if (isAnyOf(elem
.getAttribute("translate"), ["", "yes"])) {
115 } else if (isAnyOf(elem
.getAttribute("translate"), ["no"])) {
121 if (elem
.hasAttribute("abbr") &&
122 elem
.tagName
=== "TH") {
123 translateAttribute(elem
, "abbr");
125 if (elem
.hasAttribute("alt") &&
126 isAnyOf(elem
.tagName
, ["AREA", "IMG", "INPUT"])) {
127 translateAttribute(elem
, "alt");
129 if (elem
.hasAttribute("download") &&
130 isAnyOf(elem
.tagName
, ["A", "AREA"])) {
131 translateAttribute(elem
, "download");
133 if (elem
.hasAttribute("label") &&
134 isAnyOf(elem
.tagName
, ["MENUITEM", "MENU", "OPTGROUP",
135 "OPTION", "TRACK"])) {
136 translateAttribute(elem
, "label");
138 // FIXME: Should update "lang"
139 if (elem
.hasAttribute("placeholder") &&
140 isAnyOf(elem
.tagName
, ["INPUT", "TEXTAREA"])) {
141 translateAttribute(elem
, "placeholder");
143 if (elem
.hasAttribute("title")) {
144 translateAttribute(elem
, "title");
146 if (elem
.hasAttribute("value") &&
147 elem
.tagName
=== "INPUT" &&
148 isAnyOf(elem
.getAttribute("type"), ["reset", "button", "submit"])) {
149 translateAttribute(elem
, "value");
153 for (let i
= 0; i
< elem
.childNodes
.length
; i
++) {
154 const node
= elem
.childNodes
[i
];
155 if (node
.nodeType
=== node
.ELEMENT_NODE
) {
156 process(node
, enabled
);
157 } else if (node
.nodeType
=== node
.TEXT_NODE
&& enabled
) {
158 translateTextNode(node
);
163 process(document
.body
, true);
167 export const l10n
= new Localizer();
168 export default l10n
.get.bind(l10n
);