{"id":13454645,"url":"https://github.com/pid/speakingurl","last_synced_at":"2025-05-14T04:07:34.346Z","repository":{"id":8567402,"uuid":"10195075","full_name":"pid/speakingurl","owner":"pid","description":"Generate a slug – transliteration with a lot of options","archived":false,"fork":false,"pushed_at":"2024-03-15T00:57:14.000Z","size":1261,"stargazers_count":1119,"open_issues_count":29,"forks_count":83,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-05-10T21:19:28.994Z","etag":null,"topics":["slug","slugifier","speakingurl","transliteration"],"latest_commit_sha":null,"homepage":"http://pid.github.io/speakingurl/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pid.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-05-21T12:29:41.000Z","updated_at":"2025-05-10T01:38:07.000Z","dependencies_parsed_at":"2024-06-18T11:27:47.618Z","dependency_job_id":null,"html_url":"https://github.com/pid/speakingurl","commit_stats":{"total_commits":404,"total_committers":33,"mean_commits":"12.242424242424242","dds":0.4900990099009901,"last_synced_commit":"563da7ebd8c957804de43a92359d6e53796c3226"},"previous_names":[],"tags_count":80,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pid%2Fspeakingurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pid%2Fspeakingurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pid%2Fspeakingurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pid%2Fspeakingurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pid","download_url":"https://codeload.github.com/pid/speakingurl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254069215,"owners_count":22009510,"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":["slug","slugifier","speakingurl","transliteration"],"created_at":"2024-07-31T08:00:56.314Z","updated_at":"2025-05-14T04:07:34.324Z","avatar_url":"https://github.com/pid.png","language":"JavaScript","readme":"SpeakingURL\n===========\n\n[![Build Status](https://travis-ci.org/pid/speakingurl.svg)](https://travis-ci.org/pid/speakingurl)\n[![NPM version](https://badge.fury.io/js/speakingurl.svg)](https://badge.fury.io/js/speakingurl)\n[![Bower version](https://badge.fury.io/bo/speakingurl.svg)](https://badge.fury.io/bo/speakingurl)\n[![Gem Version](https://badge.fury.io/rb/speakingurl-rails.svg)](https://badge.fury.io/rb/speakingurl-rails)\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/pid/speakingurl?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n[![Flattr](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/1418477/pidspeakingurl-on-GitHub)\n\n\n\u003e Generate a slug with a lot of options; create a so-called [Semantic URL](https://en.wikipedia.org/wiki/Semantic_URL) or 'Clean URL' or 'Pretty URL' or 'nice-looking URL' or 'Speaking URL' or 'user-friendly URL' or 'SEO-friendly URL' from a string. This module aims to transliterate the input string.\n\nFor use in browser and server - no dependencies!\n\n##### NPM Badge\n\n[![Module Status](https://nodei.co/npm/speakingurl.png?downloads=true\u0026stars=true)](https://npmjs.org/package/speakingurl)\n\nInstallation\n------------\n\n#### [npm](https://npmjs.org/package/speakingurl)\n\n```shell\nnpm install speakingurl --save\n```\n\n#### [yarn](https://yarnpkg.com)\n\n```shell\nyarn add speakingurl --dev\n```\n\n#### [Bower](https://bower.io)\n\n```shell\nbower install --save speakingurl\n```\n\n#### [Component](https://github.com/component/component)\n\n```shell\ncomponent install pid/speakingurl\n```\n\n#### [Ruby on Rails](http://rubyonrails.org/)\n\n```ruby\n# Add to Gemfile\ngem 'speakingurl-rails'\n```\n\n#### [Download Package](https://github.com/pid/speakingurl/releases)\n\ncopy the file speakingurl.min.js to your script directory\n\n#### [CDN/cloudflare](https://www.cloudflare.com/)\n\navailable versions:\n\n-\t[www.cdnjs.com/libraries/speakingurl/](https://cdnjs.com/libraries/speakingurl/)\n-\tuse [//cdnjs.cloudflare.com/ajax/libs/speakingurl/14.0.1/speakingurl.min.js](https://cdnjs.cloudflare.com/ajax/libs/speakingurl/14.0.1/speakingurl.min.js)\n\n#### [CDN/maxcdn](https://www.maxcdn.com/)\n\navailable versions:\n\n-\t[www.jsdelivr.com/#!speakingurl](https://www.jsdelivr.com/package/npm/speakingurl)\n-\tuse [//cdn.jsdelivr.net/npm/speakingurl@14.0.1/speakingurl.min.js](https://cdn.jsdelivr.net/npm/speakingurl@14.0.1/speakingurl.min.js)\n\nUsage\n-----\n\n### getSlug(input, [options]);\n\n`input`: {string} to convert\n\n`options` {object|string} config object or separator string (see below)\n\n-\t`options` {object}\n\n\t-\t`separator` {string} default: '-'\n\t\t-\tchar that replaces the whitespaces\n\t-\t`lang` {string|boolean} default: 'en' // ISO 639-1 Codes\n\t\t-\tlanguage specific transliteration (\n\t\t\t-\t'ar' // Arabic\n\t\t\t-\t'az' // Azerbaijani\\*\n\t\t\t-\t'cs' // Czech\n\t\t\t-\t'de' // German\n\t\t\t-\t'dv' // Divehi\n\t\t\t-\t'en' // English\n\t\t\t-\t'es' // Spanish\n            -   'fa' // Persian\n            -   'fi' // Finnish\n\t\t\t-\t'fr' // French\n            -   'ge' // Georgian\n\t\t\t-\t'gr' // Greek\\*\n\t\t\t-\t'hu' // Hungarian\n\t\t\t-\t'it' // Italian\n\t\t\t-\t'lt' // Lithuanian\\*\n\t\t\t-\t'lv' // Latvian\n\t\t\t-\t'my' // Burmese\n\t\t\t-\t'mk' // Macedonian\\*\n\t\t\t-\t'nl' // Dutch\n\t\t\t-\t'pl' // Polish\n\t\t\t-\t'pt' // Portuguese\n\t\t\t-\t'ro' // Romanian\n\t\t\t-\t'ru' // Russian\n\t\t\t-\t'sv' // Swedish\n\t\t\t-\t'sk' // Slovak\n\t\t\t-\t'sr' // Serbian\\*\n\t\t\t-\t'tr' // Turkish\n\t\t\t-\t'uk' // Ukranian\n\t\t\t-\t'vn' // Vietnamese\n\t-\t`symbols` {boolean} default: true\n\t\t-\tfalse -\u003e don't convert symbols\n\t\t-\ttrue -\u003e convert symbols according to the 'lang' setting\n\t-\t`maintainCase` {boolean} default: false\n\t\t-\ttrue -\\\u003e maintain case chars\n\t\t-\tfalse -\\\u003e convert all chars to lower case\n\t-\t`titleCase` {boolean|array} default: false\n\t\t-\ttrue -\\\u003e convert input string to title-case\n\t\t-\tarray -\\\u003e titlecase = true, but omit the words from in the array\n\t-\t`truncate` {number} default: 0\n\t\t-\t0 -\\\u003e don't trim length\n\t\t-\t\\\u003e= 1 -\\\u003e trim to max length while not breaking any words\n\t-\t`uric` {boolean} default: false\n\t\t-\ttrue -\\\u003e additionally allow chars: \";\", \"?\", \":\", \"@\", \"\u0026\", \"=\", \"+\", \"\\$\", \",\", \"/\"\n\t\t-\tfalse\n\t-\t`uricNoSlash` {boolean} default: false\n\t\t-\ttrue -\\\u003e additionally allow chars: \";\", \"?\", \":\", \"@\", \"\u0026\", \"=\", \"+\", \"\\$\", \",\"\n\t-\t`mark` {boolean} default: false\n\t\t-\ttrue -\\\u003e additionally allow chars: \"-\", \"\\_\", \".\", \"!\", \"~\", \"\\*\", \"'\", \"(\", \")\"\n\t-\t`custom` {object|array} default: {}\n\t\t-\tobject -\\\u003e custom map for translation, overwrites all i.e. { '\u0026': '\\#', '\\*': ' star ' }\n\t\t-\tarray -\\\u003e add chars to allowed charMap (see example)\n\n-\t`options` {string} separator\n\nnotes: default only Base64 chars are allowed (/A-Za-z0-9\\_-/), setting `uric`, `uricNoSlash` or/and `mark` to `true` will add the specified chars to the list of allowed characters. The separator-character is always allowed.\n\n##### Node.js\n\n```js\nvar getSlug = require('speakingurl');\n```\n\n##### Browser\n\n```html\n\u003cscript src=\"bower_components/speakingurl/speakingurl.min.js\"\u003e\u003c/script\u003e\n```\n\n#### Ruby on Rails\n\n```ruby\n# Add to application.js\n//= require speakingurl\n```\n\n#### Examples\n\n```js\nvar slug;\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\");\nconsole.log(slug); // Output: schoener-titel-laesst-gruessen-bel-ete\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", '*');\nconsole.log(slug); // Output: schoener*titel*laesst*gruessen*bel*ete\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n        separator: '_'\n\t});\nconsole.log(slug); // Output: schoener_titel_laesst_gruessen_bel_ete\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n        uric: true\n\t});\nconsole.log(slug); // Output: schoener-titel-laesst-gruessen?-bel-ete\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n    \turicNoSlash: true\n\t});\nconsole.log(slug); // Output: schoener-titel-laesst-gruessen?-bel-ete\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n    \tmark: true\n\t});\nconsole.log(slug); // Output: schoener-titel-laesst-gruessen!-bel-ete-!\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n    \ttruncate: 20\n\t});\nconsole.log(slug); // Output: schoener-titel\n\nslug = getSlug(\"Schöner Titel läßt grüßen!? Bel été !\", {\n\t    maintainCase: true\n\t});\nconsole.log(slug); // Output: Schoener-Titel-laesst-gruessen-Bel-ete\n\nslug = getSlug(\"Äpfel \u0026 Birnen!\", {\n\t    lang: 'de'\n\t});\nconsole.log(slug); // Output: aepfel-und-birnen\n\nslug = getSlug(\"မြန်မာ သာဓက\", {\n\t    lang: 'my'\n\t});\nconsole.log(slug); // Output: myanma-thadak\n\nslug = getSlug('މިއަދަކީ ހދ ރީތި ދވހކވ', {\n        lang: 'dv'\n    });\nconsole.log(slug); // Output: miadhakee hd reethi dvhkv\n\nslug = getSlug(\"Apple \u0026 Pear!\", {\n\t    lang: 'en' // lang: \"en\" is default, just to clarify\n\t});\nconsole.log(slug); // Output: apple-and-pear\n\nslug = getSlug('Foo \u0026 Bar * Baz', {\n\t    custom: {\n\t        '\u0026': ' doo '\n\t    },\n\t    uric:true\n\t});\nconsole.log(slug); // Output: foo-doo-bar-baz\n\nslug = getSlug('Foo ♥ Bar');\nconsole.log(slug); // Output: foo-love-bar\n\nslug = getSlug('Foo \u0026 Bar | (Baz) * Doo', {\n\t    custom: {\n\t        '*': 'Boo'\n\t    },\n\t    mark:true\n\t});\nconsole.log(slug); // Output: foo-and-bar-or-(baz)-boo-doo\n\nslug = getSlug('Foo and Bar or Baz', {\n\t    custom: {\n\t        'and': 'und',\n\t        'or': ''\n\t    }\n\t});\nconsole.log(slug); // Output: foo-und-bar-baz\n\nslug = getSlug('[Knöpfe]', {\n\t\tcustom: [\n\t\t\t'[',\n\t\t\t']'\n\t\t]\n\t});\nconsole.log(slug); // Output: [knoepfe]\n\nslug = getSlug('NEXUS4 only $299');\nconsole.log(slug); // Output: nexus-4-only-usd299\n\nslug = getSlug('NEXUS4 only €299', {\n\t    maintainCase: true\n\t});\nconsole.log(slug); // Output: NEXUS-4-only-EUR299\n\nslug = getSlug('Don\\'t drink and drive', {\n\t    titleCase: true\n\t});\nconsole.log(slug); // Output: Don-t-Drink-And-Drive\n\nslug = getSlug('Don\\'t drink and drive', {\n\t    titleCase: ['and']\n\t});\nconsole.log(slug); // Output: Don-t-Drink-and-Drive\n\nslug = getSlug('Foo \u0026 Bar ♥ Foo \u003c Bar', {\n\t    lang: false\n\t});\nconsole.log(slug); // Output: foo-bar-foo-bar\n\nslug = getSlug('Foo \u0026 Bar ♥ Foo \u003c Bar', {\n\t    symbols: false\n\t});\nconsole.log(slug); // Output: foo-bar-foo-bar\n\nslug = getSlug('ä♥ä', {\n\t\tlang: 'tr',\n\t    symbols: false\n\t});\nconsole.log(slug); // Output: a\n```\n\n### createSlug([options])\n\n`options`: {object|string} config object or separator string (see above)\n\nCreate your own specially configured function.\n\n```js\nvar options = {\n\t    maintainCase: true,\n\t    separator: '_'\n\t};\n\nvar mySlug = require('speakingurl').createSlug(options);\n// in browser:\n// var mySlug = createSlug(options);\n\nvar slug = mySlug(\"Schöner Titel läßt grüßen!? Bel été !\");\nconsole.log(slug); // Output: Schoener_Titel_laesst_gruessen_Bel_ete\n```\n\nCreate your own specially configured function with title-case feature.\n\n```js\nvar options = {\n\t    titleCase: [\n\t        \"a\",\"an\",\"and\",\"as\",\"at\",\"but\",\n\t        \"by\",\"en\",\"for\",\"if\",\"in\",\"nor\",\n\t        \"of\",\"on\",\"or\",\"per\",\"the\",\"to\",\"vs\"\n\t    ]\n\t};\n\nvar mySlug = require('speakingurl').createSlug(options);\n// in browser:\n// var mySlug = createSlug(options);\n\nvar slug = mySlug('welcome to the jungle');\nconsole.log(slug); // Output: Welcome-to-the-Jungle\n```\n\nChangelog\n---------\n\nsee [CHANGELOG.md](https://raw.github.com/pid/speakingurl/master/CHANGELOG.md)\n\nTests\n-----\n\n[![Build Status](https://travis-ci.org/pid/speakingurl.svg)](https://travis-ci.org/pid/speakingurl)\n\n```shell\nnpm test\n```\n\nContribution\n------------\n\n```shell\n\n# fork pid/speakingurl on Github\n$ git clone git@github.com:\u003cYOUR_USER\u003e/speakingurl.git\n$ cd speakingurl\n$ npm install\n# add your stuff\n# add tests\n# add example for new feature\n# add release info to CHANGELOG.md\n# add description/example to README.md\n$ gulp\n$ commit files (speakingurl.min.js,...)\n# if everything works fine, commit, push to your repository\n# create pull request\n```\n\nRelease\n-------\n\n```shell\n$ gulp bumpup --patch  # --minor # --major\n$ gulp\n$ gulp release\n```\n\nRelease to RubyGems.org\n-----------------------\n\n```shell\n$ gulp\n$ gem build speakingurl-rails.gemspec\n$ gem push speakingurl-rails-x.x.x.gem\n```\n\nReferences\n----------\n\n-\thttps://tools.ietf.org/html/rfc3986\n-\thttps://en.wikipedia.org/wiki/Transliteration\n\nUse in other environments\n-------------------------\n\n-\t[SpeakingURL with AngularJS](https://github.com/zappan/angular-speakingurl)\n-\t[SpeakingURL with Meteor](https://github.com/ongoworks/meteor-speakingurl)\n-\t[SpeakingURL with Ruby on Rails](https://rubygems.org/gems/speakingurl-rails)\n\nPorts\n-----\n\n-\tJava https://github.com/Weltraumschaf/speakingurl thanks to[@Weltraumschaf](https://github.com/Weltraumschaf/)\n\nCredits\n-------\n\n-\t[@dypsilon](https://github.com/dypsilon/)\n-\t[@simov](https://github.com/simov/)\n-\t[@henrikjoreteg](https://github.com/henrikjoreteg/)\n\n[License](https://raw.github.com/pid/speakingurl/master/LICENSE)\n----------------------------------------------------------------\n\nThe BSD 3-Clause License (BSD3)\n\nCopyright (c) 2013-2017 Sascha Droste pid@posteo.net All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n-\tRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n-\tRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n-\tNeither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n","funding_links":[],"categories":["Packages","包","JavaScript","目录","URL","8. 路由和链接(Routing And URLs)","Number"],"sub_categories":["URL","Text"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpid%2Fspeakingurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpid%2Fspeakingurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpid%2Fspeakingurl/lists"}