diff --git a/app/js/locales/Readme.md b/app/js/locales/Readme.md new file mode 100644 index 00000000..10ab8aac --- /dev/null +++ b/app/js/locales/Readme.md @@ -0,0 +1,233 @@ +# Localization guide for Webogram + +## Adding/updating a new locale/language + +Adding a new locale is pretty easy, all you got to do is: + +1. ensure that the angular-locale file `vendor/angular/i18n/angular-locale_.js` exists. If not copy one of the others being most similar to your target locale and adapt it accordingly. See also the [angular docs](https://docs.angularjs.org/guide/i18n). +2. copy `js/locales/en-us.json` to `js/locales/.json` +3. without changing the key strings translate and change the value strings into your target locale +4. add your locale in js/i18n.js to the object of supported languages with locale and its native name so it will be listed in the settings +5. enjoy your awesome new webogram in your own language! + +You may also want to join the project on [transifex](https://www.transifex.com/projects/p/telegram-web/). + +### Details +#### The locale string +The locale string which is also part of the filenames consists of the lower case two character language code and the two character country code separated by a hyphen with the country code being optional, e.g: +* en-us +* en-au +* de-de + +#### Step 1: the angular locale +The files in `vendor/angular/i18n/` contain the `ngLocale` module in its various localizations which provides the `$locale` service which in turn is used by many angular functions especially for formatting times and dates and a little pluralization. +There should already be a file for almost every language so you most probably won't have to create your own. +For more see the [angular docs](https://docs.angularjs.org/guide/i18n). + +#### Step 2: copy the template +`js/locales/en-us.json` should provide you with all the localization strings currently in use in webogram and therefore be a complete template to begin with. +It's basically just a json-encoded javascript object with the keys being the message ids and the values being the corresponding translations. + +#### Step 3: adjusting the translations +The values may contain very simple markdown syntax, numbered and named parameters depending on how and where the messages are used (see also below). +Parameters are enclosed in curly braces and can be numbered (starting with 0) and/or named, but the order in the strings doesn't matter. +Here a few examples: +> "user_status_last_seen": "last seen {0}", +> "settings_modal_recent_updates": "Recent updates (ver. {version})" + +The parameters can be parameterized too in which case the parameter name/number is followed by a colon and its parameters which are delimited by a pipe (`|`). + +Example: + +> Please, install {chrome-link: http://google.com/chrome | Google Chrome} or use {telegram-link: https://telegram.org/ | mobile app} instead. + +which would end up as + +> Please, install Google Chrome or use mobile app instead. + +You could alter the url in this example to point to the language specific version of the original url. + +Then there are some strings like this: +> "contacts_modal_pluralize_new_group_members": "{'one': '1 participant', 'other': '{} participants'}", + +which are used in the `when` attributes of elements compiled by the [ngPluralize](https://docs.angularjs.org/api/ng/directive/ngPluralize) module and allow for different strings depending on the (number) value of the bound parameter and there must be valid json syntax. +Here again see the [angular docs](https://docs.angularjs.org/guide/i18n). +Such strings will have the word _pluralize_ in their key. + +And finally: strings which keys have a `_md` suffix get parsed by a simple markdown parser that places everything between `**`s in `` tags and replaces newlines with `
` e.g.: +> "welcome_text_1_md": "This is an unofficial web-client for the **Telegram Messenger**.", + +becomes +```html +This is an unofficial web-client for the Telegram Messenger. +``` + +Including html markup in the messages directly isn't supported and any contained markup will be escaped before inserting. + +#### Step 4: adding the newly created locale +The final step is to add the new locale to the list with supported (i.e. existing) locales for webogram in the factory of the localization function `_` in `js/i18n.js`. +The key for this is the locale string while the value is the name of the language to be displayed in the settings. +After adding to the list (and perhaps restarting the app) it appears in the select input and can be used. + +Additionally you can add your locale to the `aliases` object. This object is used when there is no locale configured yet and we're trying to guess the best fit from the browsers current language. +Since we're retrieving the browser language through `navigator.language` which may contain a locale with or without country code, we use `aliases` here to map between these and our supported locales whereby the keys are the lookup values and the values a locale we support, e.g: +```javascript +var aliases = { + 'en': 'en-us' +}; +``` +This maps a `navigator.language == 'en'` to `en-us` as locale to use. + + +## Using the i18n module while developing + +All the i18n functionality is located in the `myApp.i18n` module in `js/i18n.js` and exposed via various ways whereby all the localization is done by the `_` service. +It takes a message key and optional parameters for that key and returns the localized string with parameters incorporated. + +When adding new messages the key for that messages should be prefixed with the view name it appears in. If the message (should) contain(s) markdown-like markup (see above) it should additionally have a `_md` suffix. + +### The service: call the localization function (`_`) directly +The Service `_` can be injected into other modules and offers some ways to interact: + +```javascript +_('welcome_text_1_md'); // get a simple string +_('user_status_last_seen', '1 minute ago', ...); // with numbered parameters or +_('format_size_progress', {done: '10kB', total: '2048kB'}); // with named parameters +_.locale(); // retrieve the currently active locale, e.g. "en-us" +_.locale("en-us"); // set and load a new locale +_.supported(); // get the list of all supported locales +``` + +Note that `_` escapes any html entities appearing in the messages strings. If you want to retrieve an unmasked message - e.g. because it will be inserted in a way that escapes html again like `text()` - you can add a `_raw` suffix to the message key: +```javascript +_('welcome_text_1_md_raw'); // get a simple unmasked string +``` + +### The i18n filter +The i18n filter is basically just an alias/other way to call `_` and can be used in attributes and text nodes: + +```html + +{{"user_status_last_seen" | i18n:relativeTime}} +
{{"format_size_progress" | i18n:{done: bytesLoaded, total: totalSize} }}
+``` + +### Together with `ngPluralize` +`myApp.i18n` automatically intercepts the compilation of the [ngPluralize](https://docs.angularjs.org/api/ng/directive/ngPluralize) directive and pipes the value of the `when` attribute through `_` before `ngPluralize` evaluates it. +Therefore you have to replace the content of the `when` attribute with the key of the corresponding message for `ngPluralize`. The key should contain the word `pluralize` to indicate its usage. + +```html + + +``` +may evaluate to +```html + + 5 participants + +``` + +### The my-i18n directive +The `my-i18n` directive can be used as attribute or as element and replaces the contents of the element with the localized message. + +Simple usage: +```html +
+ +become +
Done
+Done +``` + +For messages which take parameters these are provided via (direct) child elements with a `my-i18n-param` directive. The params can be named or numbered if no name is provided. + +Simple formats: +> "settings_modal_recent_updates": "Recent updates (ver. {version})", +> "user_status_last_seen": "last seen {0}", + +```html + + + + + + + + + + 1 minute ago + + +evaluate to + + + Recent updates (ver. ) + + + + Recent updates (ver. ) + + + + last seen 1 minute ago + +``` + +As you see any other directives applied to the elements are preserved. + +Finally, if there is no message key passed to the `my-i18n` directive it looks for (direct) child elements with a `my-i18n-format` directive and takes the msgid of that instead, e.g.: + +> "im_one_typing": "{name1} is typing{dots}", + +```html +
+ + + +
+``` + +This way it is even possible to group together several formats which take (mostly) the same parameters: + +> "im_one_typing": "{name1} is typing{dots}", +> "im_two_typing": "{name1} and {name2} are typing{dots}", +> "im_many_typing": "{name1}, {name2} and {count} more are typing{dots}", + +```html +
+ + + + + + {{historyState.typing.length - 2}} + +
+ +will evaluate to (whitespace added for readability): + +
+ + + is typing + + + + + and + + are typing + + + + , + + and + {{historyState.typing.length - 2}} + more are typing + + +
+``` + +Also note the `ng-switch` directives on the `my-i18n-format` elements here so only one of the ``s is visible at a time.