{"id":17083889,"url":"https://github.com/grivos/spanomatic","last_synced_at":"2025-04-12T20:33:03.555Z","repository":{"id":201761965,"uuid":"183793843","full_name":"grivos/Spanomatic","owner":"grivos","description":"Automatically add spans to text from Android resources strings","archived":false,"fork":false,"pushed_at":"2021-06-08T19:57:07.000Z","size":536,"stargazers_count":131,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-31T15:38:07.690Z","etag":null,"topics":["android","android-library","kotlin-android","spannable"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grivos.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2019-04-27T16:01:52.000Z","updated_at":"2024-04-16T09:09:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"6f405437-1004-45ab-88fd-f9ba4257eb8a","html_url":"https://github.com/grivos/Spanomatic","commit_stats":null,"previous_names":["grivos/spanomatic"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grivos%2FSpanomatic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grivos%2FSpanomatic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grivos%2FSpanomatic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grivos%2FSpanomatic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grivos","download_url":"https://codeload.github.com/grivos/Spanomatic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223546010,"owners_count":17163002,"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":["android","android-library","kotlin-android","spannable"],"created_at":"2024-10-14T13:04:05.355Z","updated_at":"2024-11-07T16:03:28.688Z","avatar_url":"https://github.com/grivos.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spanomatic\nSpanomatic is an Android library that allows you to automatically add spans to text from resources strings.\n\n* [Getting Started](#getting-started)\n  * [Dependencies](#dependencies)\n  * [Initialization](#initialization)\n* [String Resources Annotations](#string-resources-annotations)\n  * [Supported Annotation Keys](#supported-annotation-keys)\n    * [fgColor](#fgcolor)\n    * [bgColor](#bgcolor)\n    * [relativeTextSize](#relativetextsize)\n    * [absoluteTextSize](#absolutetextsize)\n    * [drawable](#drawable)\n    * [format](#format)\n    * [quote](#quote)\n    * [bullet](#bullet)\n    * [url](#url)\n    * [leadingMargin](#leadingmargin)\n    * [typeface](#typeface)\n    * [click](#click)\n  * [Adding Support For Custom User Annotation Keys](#adding-support-for-custom-user-annotation-keys)\n* [Using Spanomatic Manually](#using-spanomatic-manually)\n  * [Format Arguments](#format-arguments)\n* [Acknowledgements](#acknowledgements)\n\n## Getting Started\n\n### Dependencies\nAdd Jitpack in your root build.gradle:\n```groovy\nallprojects {\n    repositories {\n        ...\n        maven { url 'https://jitpack.io' }\n    }\n}\n```\nSpanomatic uses the [ViewPump](https://github.com/InflationX/ViewPump) library, that provides an API for pre/post-inflation interceptors.  \nAdd these dependencies to your app module's build.gradle file:\n```groovy\ndependencies {\n    ...\n    implementation 'com.github.grivos:Spanomatic:1.2.1'\n    implementation 'io.github.inflationx:viewpump:2.0.3'\n}\n```\n\n### Initialization\nInit ViewPump and add the SpanomaticInterceptor in your app class:\n```kotlin\nclass MyApplication : Application() {\n\n    override fun onCreate() {\n        super.onCreate()\n        ViewPump.init(\n            ViewPump.builder()\n                .addInterceptor(\n                    SpanomaticInterceptor()\n                )\n                .build()\n        )\n    }\n    \n}\n```\n\nWrap your activities context:\n```kotlin\nclass BaseActivity : AppCompatActivity() {\n\n    override fun attachBaseContext(newBase: Context) {\n        super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))\n    }\n\n}\n```\n\n## String Resources Annotations\n\nIn order for Spanomatic to translate string resources annotations into spans, you need to wrap your strings in special annotations.\nThe mechanic is like so:\n```xml\n\u003cstring name=\"annotated_string\"\u003eThis part isn\\'t annotated,  \u003cannotation key=\"value\"\u003ebut this part is\u003c/annotation\u003e.\u003c/string\u003e\n```\nSpanomatic parses the string resource, looks for these annotations, and depending on the key and value, it adds the appropriate spans.\nYou can also nest annotations like so:\n```xml\n\u003cstring name=\"nested_annotations\"\u003eThis part isn\\'t annotated,  \u003cannotation key1=\"value1\"\u003e\u003cannotation key2=\"value2\"\u003ebut this part has two annotations\u003c/annotation\u003e\u003c/annotation\u003e.\u003c/string\u003e\n```\n\nSpanomatic supports several annotation keys out of the box, but you can also register handlers for custom annotation keys.\n\n### Supported Annotation Keys\n\n#### fgColor\n**Description:** Adds a `ForegroundSpan`.  \n**Possible Values:** Either a literal color hex (`\"#9C27B0\"`) or a color reference (`\"@color/material_purple\"`).  \n**Example:**\n```xml\n\u003cstring name=\"fg_color_hex\"\u003eThis text has \u003cannotation fgColor=\"#9C27B0\"\u003epurple foreground\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_fg](https://github.com/grivos/Spanomatic/blob/master/media/example_fg.png)\n\n#### bgColor\n**Description:** Adds a `BackgroundSpan`.  \n**Possible Values:** Either a literal color hex or a color reference.  \n**Example:**\n```xml\n\u003cstring name=\"bg_color_hex\"\u003eThis text has \u003cannotation bgColor=\"@color/material_green\"\u003egreen background\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_bg](https://github.com/grivos/Spanomatic/blob/master/media/example_bg.png)\n\n#### relativeTextSize\n**Description:** Adds a `RelativeSizeSpan`.  \n**Possible Values:** The size multiplier.  \n**Example:**\n```xml\n\u003cstring name=\"relative_size\"\u003eThis text is two times \u003cannotation relativeTextSize=\"2\"\u003ebigger\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_relative_size](https://github.com/grivos/Spanomatic/blob/master/media/example_relative_size.png)\n\n#### absoluteTextSize\n**Description:** Adds an `AbsoluteSizeSpan`.  \n**Possible Values:** A size identifier. Either a literal (`18dp`, `16sp`, etc.) or a reference (`\"@dimen/big_text_size\"`).  \n**Example:**\n```xml\n\u003cstring name=\"absolute_size\"\u003eThis text size is \u003cannotation absoluteTextSize=\"20dp\"\u003e20dp\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_absolute_size](https://github.com/grivos/Spanomatic/blob/master/media/example_absolute_size.png)\n\n#### drawable\n**Description:** Adds an `ImageSpan`.  \n**Possible Values:** A drawable reference and an optional alignment (either `baseline` or `bottom`). If the alignment is missing, the default is `baseline`.\u003cbr/\u003eThe optional alignment is separated from the drawable reference using the pipe character (`|`).  \n**Example:**\n```xml\n\u003cstring name=\"drawable_with_alignment\"\u003eThis is a \u003cannotation drawable=\"@drawable/ic_cake_16dp|bottom\"\u003ecake\u003c/annotation\u003e drawable span.\u003c/string\u003e\n```\n![example_drawable](https://github.com/grivos/Spanomatic/blob/master/media/example_drawable.png)\n\n#### format\n**Description:** Adds one of `StrikethroughSpan`, `StyleSpan`, `SuperscriptSpan`, `SubscriptSpan`, `UnderlineSpan`.  \n**Possible Values:**  \n\n| Value | Span | \n|---|---|\n| strikethrough | `StrikethroughSpan()` |\n| bold | `StyleSpan(Typeface.BOLD)` |\n| italic | `StyleSpan(Typeface.ITALIC)` |\n| boldItalic | `StyleSpan(Typeface.BOLD_ITALIC)` |\n| superscript | `SuperscriptSpa()` |\n| subscript | `SubscriptSpan()` |\n| underline | `UnderlineSpan()` |\n\n**Example:**\n```xml\n\u003cstring name=\"format_string\"\u003eSpanomatic supports \u003cannotation format=\"strikethrough\"\u003estrikethrough\u003c/annotation\u003e, \u003cannotation format=\"bold\"\u003ebold\u003c/annotation\u003e, \u003cannotation format=\"italic\"\u003eitalic\u003c/annotation\u003e, \u003cannotation format=\"boldItalic\"\u003ebold italic\u003c/annotation\u003e, \u003cannotation format=\"superscript\"\u003esuperscript\u003c/annotation\u003e, \u003cannotation format=\"subscript\"\u003esubscript\u003c/annotation\u003e and \u003cannotation format=\"underline\"\u003eunderline\u003c/annotation\u003e spans.\u003c/string\u003e\n```\n![example_format](https://github.com/grivos/Spanomatic/blob/master/media/example_format.png)\n\n#### quote\n**Description:** Adds a `QuoteSpan`.  \n**Possible Values:** Either empty or an optional literal color hex or a color reference.  \n**Example:**\n```xml\n\u003cstring name=\"quote\"\u003e\u003cannotation quote=\"\"\u003eThis is a quote\u003c/annotation\u003e\u003c/string\u003e\n```\n```xml\n\u003cstring name=\"quote_with_color\"\u003e\u003cannotation quote=\"#D81B60\"\u003eThis is a quote\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_quote](https://github.com/grivos/Spanomatic/blob/master/media/example_quote.png)\n\n#### bullet\n**Description:** Adds a `BulletSpan`.  \n**Possible Values:** Either empty or an optional gap width (literal dimension or a dimension reference), and an optional literal color hex or a color reference.  \n**Example:**\n```xml\n\u003cstring name=\"bullet\"\u003e\u003cannotation bullet=\"\"\u003eThis is a bullet\u003c/annotation\u003e\u003c/string\u003e\n```\n```xml\n\u003cstring name=\"bullet_with_gap\"\u003e\u003cannotation bullet=\"16dp\"\u003eThis is a bullet\u003c/annotation\u003e\u003c/string\u003e\n```\n```xml\n\u003cstring name=\"bullet_with_gap_and_color\"\u003e\u003cannotation bullet=\"16dp|#00574B\"\u003eThis is a bullet\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_bullet](https://github.com/grivos/Spanomatic/blob/master/media/example_bullet.png)\n\n#### url\n**Description:** Adds a `URLSpan`.  \n**Possible Values:** A url.  \n**Example:**\n```xml\n\u003cstring name=\"url\"\u003eThis text has a \u003cannotation url=\"https://www.google.com/\"\u003eUrlSpan\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_url](https://github.com/grivos/Spanomatic/blob/master/media/example_url.png)\n\n#### leadingMargin\n**Description:** Adds a `LeadingMarginSpan`.  \n**Possible Values:** The size of the leading margin (either a literal dimension or a dimension reference).  \n**Example:**\n```xml\n\u003cstring name=\"leading_margin\"\u003e\u003cannotation leadingMargin=\"@dimen/leading_margin\"\u003eThis text has a leading margin\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_leading_margin](https://github.com/grivos/Spanomatic/blob/master/media/example_leading_margin.png)\n\n#### typeface\n**Description:** Adds a `CustomTypefaceSpan`.  \n**Possible Values:** The name of this typeface (either a literal string or a string reference).  \n**Example:**  \nFirst, you need to register a `TypefaceProvider` (the best place to do so is in your Application `onCreate()` method):\n```kotlin\nval latoRegular = ResourcesCompat.getFont(this, R.font.lato_regular)\nval latoLight = ResourcesCompat.getFont(this, R.font.lato_light)\nval latoBold = ResourcesCompat.getFont(this, R.font.lato_bold)\nSpanomatic.typefaceProvider = object : TypefaceProvider {\n\n    override fun getTypeface(name: String): Typeface? {\n        return when (name) {\n            \"latoRegular\" -\u003e latoRegular\n            \"latoLight\" -\u003e latoLight\n            \"latoBold\" -\u003e latoBold\n            else -\u003e null\n        }\n    }\n\n}\n```\nThen we can use these typefaces in a string resource:\n\n```xml\n\u003cstring name=\"typefaces\"\u003eHere we have three different typefaces: \u003cannotation typeface=\"latoRegular\"\u003eLato Regular\u003c/annotation\u003e, \u003cannotation typeface=\"latoLight\"\u003eLato Light\u003c/annotation\u003e and \u003cannotation typeface=\"latoBold\"\u003eLato Bold\u003c/annotation\u003e\u003c/string\u003e\n```\n![example_typeface](https://github.com/grivos/Spanomatic/blob/master/media/example_typeface.png)\n\n#### click\n**Description:** Adds a `ListenableClickableSpan` (a custom `ClickableSpan` that can be registered with a click callback).\u003cbr/\u003eNote that this span doesn't add an `UnderlineSpan`, so if that's what you want, you should wrap it in another `format=\"underline\"` annotation.  \n**Possible Values:** The name of this click (so we can register a callback to the span from the code).  \n**Example:**  \n\n```xml\n\u003cstring name=\"click\"\u003eThis span is clickable: \u003cannotation format=\"underline\"\u003e\u003cannotation click=\"click1\"\u003eclick me\u003c/annotation\u003e\u003c/annotation\u003e\u003c/string\u003e\n```\n\nTo catch the onClick event, you need to register a callback like so:\n```kotlin\nclickableTextView.addSpanClickListener(\"click1\") {\n    Toast.makeText(this, \"Span was clicked\", Toast.LENGTH_SHORT).show()\n}\n```\n![example_click_toast](https://github.com/grivos/Spanomatic/blob/master/media/example_click_toast.gif)\n\n###  Adding Support For Custom User Annotation Keys\n\nYou can register your own annotation span handlers like so:\n```kotlin\nSpanomatic.setAnnotationSpanHandler(\"myCustomKey\") { annotationValue, context -\u003e\n    val myParsedValue = parseValue(annotationValue, context)\n    MyCustomSpan(myParsedValue)\n}\n```\n\nThen you can use it in your string resources:\n```xml\n\u003cstring name=\"custom\"\u003eThis span is \u003cannotation myCustomKey=\"someValue\"\u003ecustom\u003c/annotation\u003e\u003c/string\u003e\n```\n\n## Using Spanomatic Manually\n\nSpanomatic automatically adds spans in the layout inflation process, but you can also use it manually like so:\n```kotlin\nval spanned = addSpansFromAnnotations(R.string.annotated_string)\nmyTextView.text = spanned\n```\n\n### Format Arguments\n\nSpanomatic also supports format arguments:\n```xml\n\u003cstring name=\"annotated_string_with_parameters\"\u003eThis text has annotations with parameters: \u003cannotation format=\"bold\"\u003e%1$s\u003c/annotation\u003e, \u003cannotation format=\"italic\"\u003e%2$b\u003c/annotation\u003e, \u003cannotation format=\"underline\"\u003e%3$d\u003c/annotation\u003e\u003c/string\u003e\n```\n\n```kotlin\nval param1 = \"text\"\nval param2 = false\nval param3 = 5\nval spanned = addSpansFromAnnotations(R.string.annotated_string_with_parameters, param1, param2, param3)\nmyTextView.text = spanned\n```\n## Acknowledgements\n\nSpanomatic was inspired by [this blog post](https://medium.com/androiddevelopers/styling-internationalized-text-in-android-f99759fb7b8f) by Florina Muntenescu and the [Rialto](https://github.com/StylingAndroid/Rialto) library by Mark Allison.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrivos%2Fspanomatic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrivos%2Fspanomatic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrivos%2Fspanomatic/lists"}