{"id":16225603,"url":"https://github.com/evanleck/tater","last_synced_at":"2025-03-19T12:31:03.975Z","repository":{"id":59157313,"uuid":"175492790","full_name":"evanleck/tater","owner":"evanleck","description":"Minimal internationalization and localization library.","archived":false,"fork":false,"pushed_at":"2023-05-26T16:38:43.000Z","size":60,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-28T18:42:59.323Z","etag":null,"topics":["i18n","internationalization","l10n","localization"],"latest_commit_sha":null,"homepage":"https://github.com/evanleck/tater","language":"Ruby","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/evanleck.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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":"2019-03-13T20:19:44.000Z","updated_at":"2021-12-26T20:40:26.000Z","dependencies_parsed_at":"2024-10-27T20:34:05.816Z","dependency_job_id":"309ea3c8-5b6e-4fae-8a73-9beaa6317d8a","html_url":"https://github.com/evanleck/tater","commit_stats":{"total_commits":53,"total_committers":1,"mean_commits":53.0,"dds":0.0,"last_synced_commit":"10eafb44ec774bc3bae70f1b4ca5558f8ec64f7b"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanleck%2Ftater","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanleck%2Ftater/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanleck%2Ftater/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evanleck%2Ftater/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evanleck","download_url":"https://codeload.github.com/evanleck/tater/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243989576,"owners_count":20379648,"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":["i18n","internationalization","l10n","localization"],"created_at":"2024-10-10T12:45:35.814Z","updated_at":"2025-03-19T12:31:03.970Z","avatar_url":"https://github.com/evanleck.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tater\n\n[![](https://badge.fury.io/rb/tater.svg)](https://badge.fury.io/rb/tater)\n[![](https://github.com/evanleck/tater/actions/workflows/main.yml/badge.svg)](https://github.com/evanleck/tater/actions/workflows/main.yml)\n\nTater is an internationalization (i18n) and localization (l10n) library designed\nfor simplicity. It doesn't do everything that other libraries do, but that's\nby design.\n\nUnder the hood, Tater uses a Hash to store the messages, the `dig` method\nfor lookups, `strftime` for date and time localizations, and `format` for\ninterpolation. That's probably 90% of what Tater does.\n\n## Installation\n\nTater requires Ruby 2.7 or higher. To install Tater, add this line to your\napplication's Gemfile (or gems.rb):\n\n``` ruby\ngem 'tater'\n```\n\nAnd then execute:\n\n``` sh\nbundle\n```\n\nOr install it yourself by running:\n\n``` sh\ngem install tater\n```\n\n## Usage\n\n``` ruby\nrequire 'tater'\n\nmessages = {\n  'en' =\u003e {\n    'some' =\u003e {\n      'key' =\u003e 'This here string!'\n    },\n    'interpolated' =\u003e 'Hello %{you}!'\n  }\n}\n\ni18n = Tater.new(locale: 'en')\ni18n.load(messages: messages)\n\n# OR\ni18n = Tater.new(locale: 'en', messages: messages)\n\n# Basic lookup:\ni18n.translate('some.key') # =\u003e 'This here string!'\n\n# Interpolation:\ni18n.translate('interpolated', you: 'world') # =\u003e 'Hello world!'\n```\n\n## Array localization\n\nGiven an array, Tater will do it's best to join the elements of the array into a\nsentence based on how many elements there are.\n\n``` example\nen:\n  array:\n    last_word_connector: \", and \"\n    two_words_connector: \" and \"\n    words_connector: \", \"\n```\n\n``` ruby\ni18n.localize(%w[tacos enchiladas burritos]) # =\u003e \"tacos, enchiladas, and burritos\"\n```\n\n## Numeric localization\n\nNumeric localization (`Numeric`, `Integer`, `Float`, and `BigDecimal`) require\nfilling in a separator and delimiter. For example:\n\n``` example\nen:\n  numeric:\n    delimiter: ','\n    separator: '.'\n```\n\nWith that, you can do things like this:\n\n``` ruby\ni18n.localize(1000.2) # =\u003e \"1,000.20\"\n```\n\nThe separator and delimiter can also be passed in per-call:\n\n``` ruby\ni18n.localize(1000.2, delimiter: '_', separator: '+') # =\u003e \"1_000+20\"\n```\n\n## Date and time localization\n\nDate and time localization (`Date`, `Time`, and `DateTime`) require filling\nin all of the needed names and abbreviations for days and months. Here's the\nexample for French, which is used in the tests.\n\n``` example\nfr:\n  time:\n    am: 'am'\n    pm: 'pm'\n\n    formats:\n      default: '%I%P'\n      loud: '%I%p'\n\n  date:\n    formats:\n      abbreviated_day: '%a'\n      day: '%A'\n\n      abbreviated_month: '%b'\n      month: '%B'\n\n    days:\n      - dimanche\n      - lundi\n      - mardi\n      - mercredi\n      - jeudi\n      - vendredi\n      - samedi\n\n    abbreviated_days:\n      - dim\n      - lun\n      - mar\n      - mer\n      - jeu\n      - ven\n      - sam\n\n    months:\n      - janvier\n      - février\n      - mars\n      - avril\n      - mai\n      - juin\n      - juillet\n      - août\n      - septembre\n      - octobre\n      - novembre\n      - décembre\n\n    abbreviated_months:\n      - jan.\n      - fév.\n      - mar.\n      - avr.\n      - mai\n      - juin\n      - juil.\n      - août\n      - sept.\n      - oct.\n      - nov.\n      - déc.\n```\n\nThe statically defined keys for dates are `days`, `abbreviated_days`, `months`,\nand `abbreviated_months`. Only `am` and `pm` are needed for times and only if\nyou plan on using the `%p` or `%P` format strings.\n\nWith all of that, you can do something like:\n\n``` ruby\ni18n.localize(Date.new(1970, 1, 1), format: '%A') # =\u003e 'jeudi'\n\n# Or, using a key defined in \"formats\":\ni18n.localize(Date.new(1970, 1, 1), format: 'day') # =\u003e 'jeudi'\n```\n\n## Cascading lookups\n\nLookups can be cascaded, i.e. pieces of the scope of the can be lopped off\nincrementally.\n\n``` ruby\nmessages = {\n  'en' =\u003e {\n    'login' =\u003e {\n      'title' =\u003e 'Login',\n      'description' =\u003e 'Normal description.'\n\n      'special' =\u003e {\n        'title' =\u003e 'Special Login'\n      }\n    }\n  }\n}\n\ni18n = Tater.new(locale: 'en', messages: messages)\ni18n.translate('login.special.title') # =\u003e 'Special Login'\ni18n.translate('login.special.description') # =\u003e 'Tater lookup failed'\n\ni18n.translate('login.special.description', cascade: true) # =\u003e 'Normal description.'\n```\n\nWith cascade, the final key stays the same, but pieces of the scope get lopped\noff. In this case, lookups will be tried in this order:\n\n1.  `login.special.description`\n2.  `login.description`\n\nThis can be useful when you want to override some messages but don't want to\nhave to copy all of the other, non-overwritten messages.\n\nCascading can also be enabled by default when initializing an instance of Tater.\n\n``` ruby\nTater.new(cascade: true)\n```\n\nCascading is off by default.\n\n## Defaults\n\nIf you'd like to default to another value in case of a missed lookup, you can\nprovide the `:default` option to `#translate`.\n\n``` ruby\nTater.new.translate('nope', default: 'Yep!') # =\u003e 'Yep!'\n```\n\n## Procs and messages in Ruby\n\nRuby files can be used to store messages in addition to YAML, so long as the\nRuby file returns a `Hash` when evaluated.\n\n``` ruby\n{\n  'en' =\u003e {\n    ruby: proc do |key, options = {}|\n      \"Hey #{ key }!\"\n    end\n  }\n}\n```\n\n## Multiple locales\n\nIf you would like to check multiple locales and pull the first matching one out,\nyou can pass the `:locales` option to initialization or the `translate` method\nwith an array of top-level locale keys.\n\n``` ruby\nmessages = {\n  'en' =\u003e {\n    'title' =\u003e 'Login',\n    'description' =\u003e 'English description.'\n  },\n  'fr' =\u003e {\n    'title' =\u003e 'la connexion'\n  }\n}\n\ni18n = Tater.new(messages: messages)\ni18n.translate('title', locales: %w[fr en]) # =\u003e 'la connexion'\ni18n.translate('description', locales: %w[fr en]) # =\u003e 'English description.'\n\n# OR\ni18n = Tater.new(messages: messages, locales: %w[fr en])\ni18n.translate('title') # =\u003e 'la connexion'\ni18n.translate('description') # =\u003e 'English description.'\n```\n\nLocales will be tried in order and whichever one matches first will be returned.\n\n## Limitations\n\n- It is not plug-able, it does what it does and that's it.\n- It doesn't handle pluralization yet, though it may in the future.\n\n## Why?\n\nBecause [Ruby I18n](https://github.com/ruby-i18n/i18n) is amazing and I wanted\nto try to create a minimum viable implementation of the bits of I18n that I\nuse 90% of the time. Tater is a single file that handles the basics of lookup\nand interpolation.\n\n## Trivia\n\nI was originally going to call this library \"Translator\" but with a\n[numeronym](https://en.wikipedia.org/wiki/Numeronym) like I18n: \"t8r\". I looked\nat it for a while but I read it as \"tater\" instead of \"tee-eight-arr\" so I\nfigured I'd just name it Tater. Tater the translator.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanleck%2Ftater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevanleck%2Ftater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanleck%2Ftater/lists"}