{"id":20277352,"url":"https://github.com/bitjson/s18n","last_synced_at":"2025-04-11T05:50:39.560Z","repository":{"id":29673265,"uuid":"33215540","full_name":"bitjson/s18n","owner":"bitjson","description":"Semantic localization for html.","archived":false,"fork":false,"pushed_at":"2020-11-14T18:08:12.000Z","size":88,"stargazers_count":23,"open_issues_count":24,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-25T03:51:10.497Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitjson.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-31T23:24:00.000Z","updated_at":"2023-05-17T05:42:37.000Z","dependencies_parsed_at":"2022-09-03T16:50:19.154Z","dependency_job_id":null,"html_url":"https://github.com/bitjson/s18n","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitjson%2Fs18n","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitjson%2Fs18n/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitjson%2Fs18n/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitjson%2Fs18n/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitjson","download_url":"https://codeload.github.com/bitjson/s18n/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248351425,"owners_count":21089271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T13:18:05.646Z","updated_at":"2025-04-11T05:50:39.541Z","avatar_url":"https://github.com/bitjson.png","language":"JavaScript","readme":"[![npm version](https://badge.fury.io/js/s18n.svg)](https://www.npmjs.com/package/s18n) [![Build Status](https://travis-ci.org/bitjson/s18n.svg)](https://travis-ci.org/bitjson/s18n) [![Coverage Status](https://coveralls.io/repos/bitjson/s18n/badge.svg)](https://coveralls.io/r/bitjson/s18n) [![Dependency Status](https://david-dm.org/bitjson/s18n.svg)](https://david-dm.org/bitjson/s18n)\n\n# Semantic Localization – s18n\nS18n parses the content of html elements and attributes to extract text for translation. The automatically generated locale file can then be translated into multiple languages and used by s18n to localize the website or application.\n\nThis can be particularly powerful for static-generated sites and applications. Gulp users interested in this use-case should see [**gulp-l10n**](https://github.com/bitjson/gulp-l10n), which wraps s18n.\n\n## s18n vs. i18n\nS18n provides a simpler, automated alternative to traditional `i18n` (internationalization) libraries, in that it doesn't require outfitting application templates and content with underscore (`_()`) and other i18n functions.\n\n## Example\nThis example uses the s18n CLI. Given the following `original.html` file:\n\n```html\n\u003ch1\u003efoo\u003c/h1\u003e\n\u003cimg alt=\"bar\"\u003e\n\u003cfoo s18n\u003ebaz\u003c/foo\u003e\n```\n\nUsing the CLI's extract command in the same directory (with default element, attribute, and directive options):\n\n```bash\n$ s18n extract \u003e 'en.json'\n```\n\nThe following `locale` is saved to `en.json`:\n\n```json\n{\n  \"37b51d19\": \"bar\",\n  \"73feffa4\": \"baz\",\n  \"acbd18db\": \"foo\"\n}\n```\n\nThis locale can be translated – or for testing, s18n mapped to a simulated locale:\n\n```bash\n$ s18n map 'en.json' \u003e 'fr.json'\n```\n\nProducing `fr.json`:\n\n```json\n{\n  \"37b51d19\": \"bár\",\n  \"73feffa4\": \"báz\",\n  \"acbd18db\": \"fóó\"\n}\n```\n\nThis can then be used to test localization for the original file:\n\n```bash\n$ s18n 'original.html' -l 'fr.json' \u003e 'translated.html'\n```\n\n```html\n\u003ch1\u003efóó\u003c/h1\u003e\n\u003cimg alt=\"bár\"\u003e\n\u003cfoo s18n\u003ebáz\u003c/foo\u003e\n```\n\n# Command-Line Interface\n**Please note**: some CLI options are not yet implemented for the `map` command. Pull requests welcome!\n\nTo access the CLI system-wide, s18n can be installed globally using [npm](https://docs.npmjs.com/getting-started/installing-node):\n\n```bash\n$ npm install -g s18n\n```\n\nFor CLI usage information:\n\n```bash\n$ s18n\n$ s18n extract --help\n$ s18n localize --help\n$ s18n map --help\n```\n\nCLI tests are not currently included in test coverage.\n\n# Node API\n\n```bash\n$ npm install s18n\n```\n\n## Extracting the Native Locale\nS18n parses html content and extracts strings from selected html elements and attributes. A hash of each string is used to identify it, and all hash-string pairs are stored in a `locale` object.\n\n### s18n.extract(html, [extract options])\nThe `extract` method accepts a string of html and (optionally) an `extract options` object. It returns a locale object.\n\n```js\nvar s18n = require('s18n');\n\nvar html = '\u003ctitle\u003efoo\u003c/title\u003e' +\n           '\u003cimg alt=\"bar\"\u003e' +\n           '\u003cfoo s18n\u003ebaz\u003c/foo\u003e';\n\nvar locale = s18n.extract(html);\n```\n\nThe `locale` object:\n\n```json\n{\n  \"acbd18db\": \"foo\",\n  \"37b51d19\": \"bar\",\n  \"73feffa4\": \"baz\"\n}\n```\n\n### s18n.extractFiles(glob, [extract options]).then(function(locale))\nThe `extractFiles` method is asynchronous and accepts a [globby](https://github.com/sindresorhus/globby) glob and an `extract options` object (optional) and returns a promise. The method asynchronously extracts localizations from each file selected by the glob and combines them into a single `locale` object.\n\n```js\nvar s18n = require('s18n');\n\nvar htmlFiles = 'src/**/*.html';\n\nvar locale = s18n.extractFiles(htmlFiles)\n  .then(function(nativeLocale){\n    myApp.doSomething(nativeLocale);\n   })\n  .catch(function(err){\n    log.error(err);\n  });\n```\n\n### Extract Options\nS18n's default extraction options will be ideal for most sites and applications, but advanced customization is possible.\n\n#### elements\n- Accepts: _String_, _Array of Strings_\n- Default: `['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'small', 'a', 'button']`\n\nS18n will extract the full contents of all selected elements.\n\n#### attributes\n- Accepts: _String_, _Array of Strings_\n- Default: `['alt', 'title']`\n\nS18n will extract the full contents of all selected attributes.\n\n#### directives\n- Accepts: _String_, _Array of Strings_\n- Default: `['s18n', 'translate=yes']`\n\nS18n will extract the full contents of all elements with the following attributes. To localize only elements with an attribute set to a certain value, use an `=` character between the directive and the necessary value.\n\nBy default, the [W3C standard `translate=yes` attribute](http://www.w3.org/TR/2013/CR-html5-20130806/dom.html#attr-translate) is honored.\n\n#### cancelers\n- Accepts: _String_, _Array of Strings_\n- Default: `'cancel-s18n'`\n\nS18n will not extract the contents of any elements with the following attributes. To cancel localization of elements with an attribute set to a certain value, use an `=` character between the directive and the necessary value.\n\nCancelers take precedence over any setters/selectors.\n\n#### excluders\n- Accepts: _String_, _Array of Strings_\n- Default: `['s18n-exclude', 'translate=no']`\n\nS18n will completely ignore any elements with the following attributes, canceling localization of all sub-elements. To exclude localization of elements with an attribute set to a certain value, use an `=` character between the directive and the necessary value.\n\nBy default, the [W3C standard `translate=no` attribute](http://www.w3.org/TR/2013/CR-html5-20130806/dom.html#attr-translate) is honored.\n\n#### attributeSetter\n- Accepts: _String_\n- Default: `'s18n-attrs'`\n\nS18n will extract the full contents of all attributes provided in the `attributeSetter` attribute.\n\n```html\n\u003cmeta name=\"description\" content=\"Friendly description.\" s18n-attrs=\"content\"\u003e\n\u003cimg src=\"img/en/1.png\" title=\"test\" alt=\"test2\" s18n-attrs=\"src title alt\"\u003e\n```\n\n#### attributeCanceler\n- Accepts: _String_\n- Default: `'cancel-s18n-attrs'`\n\nS18n will not extract the contents of any attributes provided in the `attributeCanceler` attribute.\n\nAttribute cancels take precedence over any attribute setters/selectors.\n\n```html\n\u003cimg src=\"img/2.png\" title=\"words\" alt=\"words2\" cancel-s18n-attrs=\"title alt\"\u003e\n```\n\n#### hashAlgorithm\n- Accepts: _Algorithm name – String_\n- Default: `'md5'`\n\nS18n will use this algorithm to take the hash of each string. `hashAlgorithm` accepts any algorithm supported by [Node's `crypto.createHash()`](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm) method.\n\n#### hashLength\n- Accepts: _Positive integer – Number_\n- Default: `8`\n\nS18n will truncate hashes to this length when indexing strings in the `locale` object.\n\n#### trimWhitespace\n- Accepts: `true` or `false`\n- Default: `true`\n\nS18n will trim whitespace from each string (using javascript's `String.prototype.trim()`) if this option is set to `true`. This ensures matching phrases aren't treated as unique strings due to surrounding whitespace.\n\n#### output\n- Accepts: `object` or `string`\n- Default: `object`\n\nBased on this option, the `extract` method returns the extracted locale as a javascript object or as a formatted JSON string.\n\n## Localize\nTo localize html, s18n searches through the html for strings in the `nativeLocale`, replacing them with the localized strings in each locale. S18n only matches strings in locations from which they could have been extracted (between `\"\"`, `''`, and `\u003e\u003c`) to avoid translating unintended strings.\n\n### s18n(html, [options])\nThe s18n method accepts an html string, a `nativeLocale`, and a `locales` object of translated `locale` objects.\n\n### Localize Settings\nBoth the `nativeLocale` and `locale` (or `locales`) settings are required.\n\n#### nativeLocale\n- Accepts: _locale object_\n- Required\n\nThe `nativeLocale` is the `locale` object returned by the `extract()` or `extractFiles()` methods. The `s18n()` method searches the html for strings in the `nativeLocale`, and replaces them with translated strings from the `locale` or `locales` setting.\n\n#### locale _or_ locales\n- Accepts: _locale Object_ or _locales Object_\n- Required\n\nThe `s18n()` method requires either the `locale` or `locales` setting.\n\n##### locale\nThe `locale` setting accepts a single, translated `locale` object. When the `locale` settings is used, `s18n()` returns a single localized html string. When `rewriteLangAttribute` is true (default), both `nativeLocalId` and `localeId` must be set.\n\n```js\nvar s18n = require('s18n');\nvar html = '\u003chtml lang=\"en\"\u003e\u003ctitle\u003efoo\u003c/title\u003e\u003cimg alt=\"bar\"\u003e\u003cfoo s18n\u003ebaz\u003c/foo\u003e\u003c/html\u003e';\nvar settings = {\n  nativeLocale: s18n.extract(html),\n  nativeLocalId: 'en',\n  locale: {\n    \"acbd18db\": \"fóó\",\n    \"37b51d19\": \"bár\",\n    \"73feffa4\": \"báz\"\n  },\n  localeId: 'accents'\n};\n\nvar content = s18n(html, settings);\n```\n\nThe `content` object:\n\n```js\n'\u003chtml lang=\"accents\"\u003e\u003ctitle\u003efóó\u003c/title\u003e\u003cimg alt=\"bár\"\u003e\u003cfoo s18n\u003ebáz\u003c/foo\u003e\u003c/html\u003e'\n```\n\n##### locales\nThe `locales` settings accepts a `locales` object. The `locales` object keys are locale ids, and the values are their respective `locale` objects. When the `locales` settings is used, `s18n()` returns an object with locale id keys mapped to translated html strings.\n\n```js\nvar s18n = require('s18n');\nvar html = '\u003chtml lang=\"en\"\u003e\u003ctitle\u003efoo\u003c/title\u003e\u003cimg alt=\"bar\"\u003e\u003cfoo s18n\u003ebaz\u003c/foo\u003e\u003c/html\u003e';\nvar settings = {\n  nativeLocale: s18n.extract(html),\n  nativeLocalId: 'en',\n  locales: {\n    'ac': { \"acbd18db\": \"fóó\", \"37b51d19\": \"bár\", \"73feffa4\": \"báz\" }\n    'a2': { \"acbd18db\": \"fó2\", \"37b51d19\": \"bá2\", \"73feffa4\": \"bá2\" }\n  }\n};\n\nvar content = s18n(html, settings);\n```\n\nThe `content` object:\n\n```js\n{\n  'ac': '\u003chtml lang=\"ac\"\u003e\u003ctitle\u003efóó\u003c/title\u003e\u003cimg alt=\"bár\"\u003e\u003cfoo s18n\u003ebáz\u003c/foo\u003e\u003c/html\u003e'\n  'a2': '\u003chtml lang=\"a2\"\u003e\u003ctitle\u003efó2\u003c/title\u003e\u003cimg alt=\"bá2\"\u003e\u003cfoo s18n\u003ebá2\u003c/foo\u003e\u003c/html\u003e'\n}\n```\n\n#### rewriteLangAttribute\n- Accepts: _Boolean_\n- Default: `true`\n\nWhen `rewriteLangAttribute` is true, the `s18n` method will replace `nativelLocaleId` with `localeId` in all html `lang` attributes. To make `s18n` output a `lang` attribute with the `nativelLocaleId` value, use the `s18n-lock-lang` attribute in the native html.\n\n```html\n\u003chtml lang=\"en\"\u003eEnglish speakers often use the word \u003ccode s18n-lock-lang=\"en\"\u003edo\u003c/code\u003e.\u003c/html\u003e\n\u003chtml lang=\"de\"\u003eEnglisch-Lautsprecher verwenden oft das Wort \u003ccode lang=\"en\"\u003edo\u003c/code\u003e.\u003c/html\u003e\n```\n\n#### nativeLocaleId\n- Accepts: _String_\n- Required when `locale` is used and `rewriteLangAttribute` is true\n\nThe language code of the native document.\n\n#### localeId\n- Accepts: _String_\n- Required when `locale` is used and `rewriteLangAttribute` is true\n\nThe language code of the locale being used to localize the document.\n\n## Testing Localization\n### Map\n### s18n.map(locale, options)\n\n```js\nvar s18n = require('s18n');\n\nvar locale = {\n  \"acbd18db\": \"foo\",\n  \"37b51d19\": \"bar\"\n}\n\nvar test = s18n.map(locale, { dictionary: 'accents' });\n\n// test =\u003e\n{\n  \"acbd18db\": \"fóó\",\n  \"37b51d19\": \"bár\"\n}\n```\n\n## Utilities\n### s18n.compareLocales(localeA, localeB, [options])\n### s18n.formatLocale(locale, [options])\n#### options\n##### output *(string)*\nOptions: `string`, `object`\n\nDefault: `object`\n\n# Contributing\nThe default Gulp task watches all files and runs tests and code coverage.\n\n```bash\n$ npm install -g gulp\n$ gulp\n```\n\n## Testing\nThis module strives to maintain passing tests with 100% coverage in every commit, and tests are run pre-commit. If you prefer, you can always skip this check with `git commit --no-verify` and squash WIP commits for pull requests later.\n\nIf you're unsure or would like help writing tests or getting to 100% coverage, please don't hesitate to open up a pull request so others can help!\n\n## Thanks\nThanks to [Stephen Pair](https://github.com/gasteve) of [bitpay/translations](https://github.com/bitpay/translations) for some of the architectural inspiration behind s18n. This module builds on the idea of using truncated hashes as identifiers for translatable strings, rather than manually developed indexes.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitjson%2Fs18n","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitjson%2Fs18n","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitjson%2Fs18n/lists"}