PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/qooxdoo/framework/source/class/qx/locale/Manager.js

https://github.com/stephaneerard/qooxdoo
JavaScript | 443 lines | 183 code | 71 blank | 189 comment | 33 complexity | 8a29be33179f619758eb83ad374eb77e MD5 | raw file
  1. /* ************************************************************************
  2. qooxdoo - the new era of web development
  3. http://qooxdoo.org
  4. Copyright:
  5. 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
  6. License:
  7. LGPL: http://www.gnu.org/licenses/lgpl.html
  8. EPL: http://www.eclipse.org/org/documents/epl-v10.php
  9. See the LICENSE file in the project's top-level directory for details.
  10. Authors:
  11. * Sebastian Werner (wpbasti)
  12. * Andreas Ecker (ecker)
  13. * Fabian Jakobs (fjakobs)
  14. ************************************************************************ */
  15. /*
  16. #require(qx.event.dispatch.Direct)
  17. #require(qx.bom.client.Locale)
  18. #require(qx.locale.LocalizedString)
  19. #cldr
  20. */
  21. /**
  22. * The qx.locale.Manager provides static translation methods (like tr()) and
  23. * general locale information.
  24. */
  25. qx.Class.define("qx.locale.Manager",
  26. {
  27. type : "singleton",
  28. extend : qx.core.Object,
  29. /*
  30. *****************************************************************************
  31. CONSTRUCTOR
  32. *****************************************************************************
  33. */
  34. construct : function()
  35. {
  36. this.base(arguments);
  37. this.__translations = qx.$$translations || {};
  38. this.__locales = qx.$$locales || {};
  39. var clazz = qx.bom.client.Locale;
  40. var locale = clazz.LOCALE;
  41. var variant = clazz.VARIANT;
  42. if (variant !== "") {
  43. locale += "_" + variant;
  44. }
  45. this.setLocale(locale || this.__defaultLocale);
  46. },
  47. /*
  48. *****************************************************************************
  49. STATICS
  50. *****************************************************************************
  51. */
  52. statics :
  53. {
  54. /**
  55. * Translate a message
  56. *
  57. * @param messageId {String} message id (may contain format strings)
  58. * @param varargs {Object} variable number of arguments applied to the format string
  59. * @return {String} The translated string
  60. * @see qx.lang.String.format
  61. */
  62. tr : function(messageId, varargs)
  63. {
  64. var args = qx.lang.Array.fromArguments(arguments);
  65. args.splice(0, 1);
  66. return qx.locale.Manager.getInstance().translate(messageId, args);
  67. },
  68. /**
  69. * Translate a plural message
  70. *
  71. * Depending on the third argument the plural or the singular form is chosen.
  72. *
  73. * @param singularMessageId {String} message id of the singular form (may contain format strings)
  74. * @param pluralMessageId {String} message id of the plural form (may contain format strings)
  75. * @param count {Integer} singular form if equals 1, otherwise plural
  76. * @param varargs {Object} variable number of arguments applied to the format string
  77. * @return {String} The translated string
  78. * @see qx.lang.String.format
  79. */
  80. trn : function(singularMessageId, pluralMessageId, count, varargs)
  81. {
  82. var args = qx.lang.Array.fromArguments(arguments);
  83. args.splice(0, 3);
  84. // assumes "Two forms, singular used for one only" (seems to be the most common form)
  85. // (http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html#Plural-forms)
  86. // closely related with bug #745
  87. if (count != 1) {
  88. return qx.locale.Manager.getInstance().translate(pluralMessageId, args);
  89. } else {
  90. return qx.locale.Manager.getInstance().translate(singularMessageId, args);
  91. }
  92. },
  93. /**
  94. * Translate a message with translation hint
  95. *
  96. * @param hint {String} hint for the translator of the message. Will be included in the .po file.
  97. * @param messageId {String} message id (may contain format strings)
  98. * @param varargs {Object} variable number of arguments applied to the format string
  99. * @return {String} The translated string
  100. * @see qx.lang.String.format
  101. */
  102. trc : function(hint, messageId, varargs)
  103. {
  104. var args = qx.lang.Array.fromArguments(arguments);
  105. args.splice(0, 2);
  106. return qx.locale.Manager.getInstance().translate(messageId, args);
  107. },
  108. /**
  109. * Mark the message for translation but return the original message.
  110. *
  111. * @param messageId {String} the message ID
  112. * @return {String} messageId
  113. */
  114. marktr : function(messageId) {
  115. return messageId;
  116. }
  117. },
  118. /*
  119. *****************************************************************************
  120. PROPERTIES
  121. *****************************************************************************
  122. */
  123. properties :
  124. {
  125. /** current locale. locale is an language code like de, de_AT, en, en_GB, fr, ... */
  126. locale :
  127. {
  128. check : "String",
  129. nullable : true,
  130. apply : "_applyLocale",
  131. event : "changeLocale"
  132. }
  133. },
  134. /*
  135. *****************************************************************************
  136. MEMBERS
  137. *****************************************************************************
  138. */
  139. members :
  140. {
  141. __defaultLocale : "C",
  142. __locale : null,
  143. __language : null,
  144. __translations : null,
  145. __locales : null,
  146. /**
  147. * Get the language code of the current locale
  148. *
  149. * This is the first part of a locale definition. The language for "de_DE" would be "de"
  150. *
  151. * @return {String} language code
  152. */
  153. getLanguage : function() {
  154. return this.__language;
  155. },
  156. /**
  157. * Get the territory code of the current locale
  158. *
  159. * This is the second part of a locale definition. The territory for "de_DE" would be "DE"
  160. *
  161. * @return {String} territory code
  162. */
  163. getTerritory : function() {
  164. return this.getLocale().split("_")[1] || "";
  165. },
  166. /**
  167. * Return the available application locales
  168. *
  169. * This corresponds to the Makefile APPLICATION_LOCALES setting
  170. *
  171. * @return {String[]} array of available locales
  172. */
  173. getAvailableLocales : function()
  174. {
  175. var locales = [];
  176. for (var locale in this.__locales)
  177. {
  178. if (locale != this.__defaultLocale) {
  179. locales.push(locale);
  180. }
  181. }
  182. return locales;
  183. },
  184. /**
  185. * Extract the language part from a locale.
  186. *
  187. * @param locale {String} locale to be used
  188. * @return {String} language
  189. */
  190. __extractLanguage : function(locale)
  191. {
  192. var language;
  193. var pos = locale.indexOf("_");
  194. if (pos == -1) {
  195. language = locale;
  196. } else {
  197. language = locale.substring(0, pos);
  198. }
  199. return language;
  200. },
  201. // property apply
  202. _applyLocale : function(value, old)
  203. {
  204. this.__locale = value;
  205. this.__language = this.__extractLanguage(value);
  206. },
  207. /**
  208. * Add a translation to the translation manager.
  209. *
  210. * If <code>languageCode</code> already exists, its map will be updated with
  211. * <code>translationMap</code> (new keys will be added, existing keys will be
  212. * overwritten).
  213. *
  214. * @param languageCode {String} language code of the translation like <i>de, de_AT, en, en_GB, fr, ...</i>
  215. * @param translationMap {Map} mapping of message identifiers to message strings in the target
  216. * language, e.g. <i>{"greeting_short" : "Hello"}</i>. Plural forms
  217. * are separate keys.
  218. * @return {void}
  219. */
  220. addTranslation : function(languageCode, translationMap)
  221. {
  222. var catalog = this.__translations;
  223. if (catalog[languageCode])
  224. {
  225. for (var key in translationMap) {
  226. catalog[languageCode][key] = translationMap[key];
  227. }
  228. }
  229. else
  230. {
  231. catalog[languageCode] = translationMap;
  232. }
  233. },
  234. /**
  235. * Add a localization to the localization manager.
  236. *
  237. * If <code>localeCode</code> already exists, its map will be updated with
  238. * <code>localeMap</code> (new keys will be added, existing keys will be overwritten).
  239. *
  240. * @param localeCode {String} locale code of the translation like <i>de, de_AT, en, en_GB, fr, ...</i>
  241. * @param localeMap {Map} mapping of locale keys to the target locale values, e.g.
  242. * <i>{"cldr_date_format_short" : "M/d/yy"}</i>.
  243. * @return {void}
  244. */
  245. addLocale : function(localeCode, localeMap)
  246. {
  247. var catalog = this.__locales;
  248. if (catalog[localeCode])
  249. {
  250. for (var key in localeMap) {
  251. catalog[localeCode][key] = localeMap[key];
  252. }
  253. }
  254. else
  255. {
  256. catalog[localeCode] = localeMap;
  257. }
  258. },
  259. /**
  260. * Translate a message using the current locale and apply format string to the arguments.
  261. *
  262. * Implements the lookup chain locale (e.g. en_US) -> language (e.g. en) ->
  263. * default locale (e.g. C). Localizes the arguments if possible and splices
  264. * them into the message. If qx.dynlocale is on, returns a {@link
  265. * LocalizedString}.
  266. *
  267. * @param messageId {String} message id (may contain format strings)
  268. * @param args {Object[]} array of objects, which are inserted into the format string
  269. * @param locale {String ? #locale} locale to be used; if not given, defaults to the value of {@link #locale}
  270. * @return {String | LocalizedString} translated message or localized string
  271. */
  272. translate : function(messageId, args, locale)
  273. {
  274. var catalog = this.__translations;
  275. return this.__lookupAndExpand(catalog, messageId, args, locale);
  276. },
  277. /**
  278. * Provide localisation (CLDR) data.
  279. *
  280. * Implements the lookup chain locale (e.g. en_US) -> language (e.g. en) ->
  281. * default locale (e.g. C). Localizes the arguments if possible and splices
  282. * them into the message. If qx.dynlocale is on, returns a {@link
  283. * LocalizedString}.
  284. *
  285. * @param messageId {String} message id (may contain format strings)
  286. * @param args {Object[]} array of objects, which are inserted into the format string
  287. * @param locale {String ? #locale} locale to be used; if not given, defaults to the value of {@link #locale}
  288. * @return {String | LocalizedString} translated message or localized string
  289. */
  290. localize : function(messageId, args, locale)
  291. {
  292. var catalog = this.__locales;
  293. return this.__lookupAndExpand(catalog, messageId, args, locale);
  294. },
  295. /**
  296. * Look up an I18N key in a catalog and expand format strings.
  297. *
  298. * Implements the lookup chain locale (e.g. en_US) -> language (e.g. en) ->
  299. * default locale (e.g. C). Localizes the arguments if possible and splices
  300. * them into the message. If qx.dynlocale is on, returns a {@link
  301. * LocalizedString}.
  302. *
  303. * @param catalog {Map} map of I18N keys and their values
  304. * @param messageId {String} message id (may contain format strings)
  305. * @param args {Object[]} array of objects, which are inserted into the format string
  306. * @param locale {String ? #locale} locale to be used; if not given, defaults to the value of {@link #locale}
  307. * @return {String | LocalizedString} translated message or localized string
  308. */
  309. __lookupAndExpand : function(catalog, messageId, args, locale)
  310. {
  311. var txt;
  312. if (!catalog) {
  313. return messageId;
  314. }
  315. if (locale) {
  316. var language = this.__extractLanguage(locale);
  317. }
  318. else
  319. {
  320. locale = this.__locale;
  321. language = this.__language;
  322. }
  323. // e.g. DE_at
  324. if (!txt && catalog[locale]) {
  325. txt = catalog[locale][messageId];
  326. }
  327. // e.g. DE
  328. if (!txt && catalog[language]) {
  329. txt = catalog[language][messageId];
  330. }
  331. // C
  332. if (!txt && catalog[this.__defaultLocale]) {
  333. txt = catalog[this.__defaultLocale][messageId];
  334. }
  335. if (!txt) {
  336. txt = messageId;
  337. }
  338. if (args.length > 0)
  339. {
  340. var translatedArgs = [];
  341. for ( var i = 0; i < args.length; i++)
  342. {
  343. var arg = args[i];
  344. if (arg && arg.translate) {
  345. translatedArgs[i] = arg.translate();
  346. } else {
  347. translatedArgs[i] = arg;
  348. }
  349. }
  350. txt = qx.lang.String.format(txt, translatedArgs);
  351. }
  352. if (qx.core.Variant.isSet("qx.dynlocale", "on")) {
  353. txt = new qx.locale.LocalizedString(txt, messageId, args);
  354. }
  355. return txt;
  356. }
  357. },
  358. /*
  359. *****************************************************************************
  360. DESTRUCTOR
  361. *****************************************************************************
  362. */
  363. destruct : function() {
  364. this.__translations = this.__locales = null;
  365. }
  366. });