nls.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  6. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  7. return new (P || (P = Promise))(function (resolve, reject) {
  8. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  9. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  10. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  11. step((generator = generator.apply(thisArg, _arguments || [])).next());
  12. });
  13. };
  14. let isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);
  15. const DEFAULT_TAG = 'i-default';
  16. function _format(message, args) {
  17. let result;
  18. if (args.length === 0) {
  19. result = message;
  20. }
  21. else {
  22. result = message.replace(/\{(\d+)\}/g, (match, rest) => {
  23. const index = rest[0];
  24. const arg = args[index];
  25. let result = match;
  26. if (typeof arg === 'string') {
  27. result = arg;
  28. }
  29. else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {
  30. result = String(arg);
  31. }
  32. return result;
  33. });
  34. }
  35. if (isPseudo) {
  36. // FF3B and FF3D is the Unicode zenkaku representation for [ and ]
  37. result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
  38. }
  39. return result;
  40. }
  41. function findLanguageForModule(config, name) {
  42. let result = config[name];
  43. if (result) {
  44. return result;
  45. }
  46. result = config['*'];
  47. if (result) {
  48. return result;
  49. }
  50. return null;
  51. }
  52. function endWithSlash(path) {
  53. if (path.charAt(path.length - 1) === '/') {
  54. return path;
  55. }
  56. return path + '/';
  57. }
  58. function getMessagesFromTranslationsService(translationServiceUrl, language, name) {
  59. return __awaiter(this, void 0, void 0, function* () {
  60. const url = endWithSlash(translationServiceUrl) + endWithSlash(language) + 'vscode/' + endWithSlash(name);
  61. const res = yield fetch(url);
  62. if (res.ok) {
  63. const messages = yield res.json();
  64. return messages;
  65. }
  66. throw new Error(`${res.status} - ${res.statusText}`);
  67. });
  68. }
  69. function createScopedLocalize(scope) {
  70. return function (idx, defaultValue) {
  71. const restArgs = Array.prototype.slice.call(arguments, 2);
  72. return _format(scope[idx], restArgs);
  73. };
  74. }
  75. export function localize(data, message, ...args) {
  76. return _format(message, args);
  77. }
  78. export function getConfiguredDefaultLocale(_) {
  79. // This returns undefined because this implementation isn't used and is overwritten by the loader
  80. // when loaded.
  81. return undefined;
  82. }
  83. export function setPseudoTranslation(value) {
  84. isPseudo = value;
  85. }
  86. /**
  87. * Invoked in a built product at run-time
  88. */
  89. export function create(key, data) {
  90. var _a;
  91. return {
  92. localize: createScopedLocalize(data[key]),
  93. getConfiguredDefaultLocale: (_a = data.getConfiguredDefaultLocale) !== null && _a !== void 0 ? _a : ((_) => undefined)
  94. };
  95. }
  96. /**
  97. * Invoked by the loader at run-time
  98. */
  99. export function load(name, req, load, config) {
  100. var _a;
  101. const pluginConfig = (_a = config['vs/nls']) !== null && _a !== void 0 ? _a : {};
  102. if (!name || name.length === 0) {
  103. return load({
  104. localize: localize,
  105. getConfiguredDefaultLocale: () => { var _a; return (_a = pluginConfig.availableLanguages) === null || _a === void 0 ? void 0 : _a['*']; }
  106. });
  107. }
  108. const language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;
  109. const useDefaultLanguage = language === null || language === DEFAULT_TAG;
  110. let suffix = '.nls';
  111. if (!useDefaultLanguage) {
  112. suffix = suffix + '.' + language;
  113. }
  114. const messagesLoaded = (messages) => {
  115. if (Array.isArray(messages)) {
  116. messages.localize = createScopedLocalize(messages);
  117. }
  118. else {
  119. messages.localize = createScopedLocalize(messages[name]);
  120. }
  121. messages.getConfiguredDefaultLocale = () => { var _a; return (_a = pluginConfig.availableLanguages) === null || _a === void 0 ? void 0 : _a['*']; };
  122. load(messages);
  123. };
  124. if (typeof pluginConfig.loadBundle === 'function') {
  125. pluginConfig.loadBundle(name, language, (err, messages) => {
  126. // We have an error. Load the English default strings to not fail
  127. if (err) {
  128. req([name + '.nls'], messagesLoaded);
  129. }
  130. else {
  131. messagesLoaded(messages);
  132. }
  133. });
  134. }
  135. else if (pluginConfig.translationServiceUrl && !useDefaultLanguage) {
  136. (() => __awaiter(this, void 0, void 0, function* () {
  137. var _b;
  138. try {
  139. const messages = yield getMessagesFromTranslationsService(pluginConfig.translationServiceUrl, language, name);
  140. return messagesLoaded(messages);
  141. }
  142. catch (err) {
  143. // Language is already as generic as it gets, so require default messages
  144. if (!language.includes('-')) {
  145. console.error(err);
  146. return req([name + '.nls'], messagesLoaded);
  147. }
  148. try {
  149. // Since there is a dash, the language configured is a specific sub-language of the same generic language.
  150. // Since we were unable to load the specific language, try to load the generic language. Ex. we failed to find a
  151. // Swiss German (de-CH), so try to load the generic German (de) messages instead.
  152. const genericLanguage = language.split('-')[0];
  153. const messages = yield getMessagesFromTranslationsService(pluginConfig.translationServiceUrl, genericLanguage, name);
  154. // We got some messages, so we configure the configuration to use the generic language for this session.
  155. (_b = pluginConfig.availableLanguages) !== null && _b !== void 0 ? _b : (pluginConfig.availableLanguages = {});
  156. pluginConfig.availableLanguages['*'] = genericLanguage;
  157. return messagesLoaded(messages);
  158. }
  159. catch (err) {
  160. console.error(err);
  161. return req([name + '.nls'], messagesLoaded);
  162. }
  163. }
  164. }))();
  165. }
  166. else {
  167. req([name + suffix], messagesLoaded, (err) => {
  168. if (suffix === '.nls') {
  169. console.error('Failed trying to load default language strings', err);
  170. return;
  171. }
  172. console.error(`Failed to load message bundle for language ${language}. Falling back to the default language:`, err);
  173. req([name + '.nls'], messagesLoaded);
  174. });
  175. }
  176. }