{"id":16224199,"url":"https://github.com/camertron/abroad","last_synced_at":"2025-04-08T01:46:52.865Z","repository":{"id":62552574,"uuid":"53900916","full_name":"camertron/abroad","owner":"camertron","description":"A set of parsers and serializers for dealing with localization file formats.","archived":false,"fork":false,"pushed_at":"2019-01-30T23:52:35.000Z","size":69,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-16T16:06:01.883Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/camertron.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-15T00:02:14.000Z","updated_at":"2019-01-30T23:52:37.000Z","dependencies_parsed_at":"2022-11-03T04:00:54.559Z","dependency_job_id":null,"html_url":"https://github.com/camertron/abroad","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/camertron%2Fabroad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camertron%2Fabroad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camertron%2Fabroad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/camertron%2Fabroad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/camertron","download_url":"https://codeload.github.com/camertron/abroad/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247761029,"owners_count":20991533,"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-10-10T12:23:12.074Z","updated_at":"2025-04-08T01:46:52.849Z","avatar_url":"https://github.com/camertron.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/camertron/abroad.svg?branch=master)](https://travis-ci.org/camertron/abroad)\n\nabroad\n====================\n\nA set of tools for serializing and extracting strings to and from a number of localization file formats. Currently supported formats are:\n\n1. YAML, both plain and Rails-style\n2. Android XML\n3. JSON key/value\n\nAdding additional extractors and serializers is straightforward; skip to the bottom of this document to learn more.\n\n## Installation\n\n`gem install abroad`, or add it to your Gemfile.\n\nThen, somewhere in your project:\n\n```ruby\nrequire 'abroad'\n```\n\n## Introduction\n\nMost application frameworks specify a way to localize (i.e. translate) UI phrases and other content. Usually this is done via flat, static files that map strings written in a source langage to translations written in any number of target languages. In Ruby on Rails, this is done via YAML files stored in the config/locales directory. Each file contains a series of nested key/value pairs, where the key is a machine-readable, globally unique identifier and the value is a human-readable bit of text meant to be displayed to users of the application. English strings go in config/locales/en.yml, Spanish strings go in config/locales/es.yml and so on. Both en.yml and es.yml contain the same set of keys, but different (translated) values for those keys.\n\nLocalization file formats are usually based on some standard format like YAML, but often extended in unique ways specific to the framework or platform. Interpreting these files can be difficult because of the various edge cases and platform-specific expectations. If you ever find yourself needing to parse or write out compatible files, consider using well-tested tools like the ones in this project.\n\n## Usage\n\nAbroad provides extractors for reading keys and values from localization files, and serializers for writing them out. The usage for each is slightly different.\n\n### Extractors\n\nLet's say you're working with this Rails YAML file:\n\n```yaml\nen:\n  welcome:\n    message: hello\n  goodbye:\n    message: goodbye\n```\n\nTo extract strings from this file, try something like this:\n\n```ruby\nAbroad.extractor('yaml/rails').open('/path/to/en.yml') do |extractor|\n  extractor.extract_each do |key, string|\n    # on first iteration, key == 'welcome.message', string == 'hello'\n    # on second iteration, key == 'goodbye.message', string == 'goodbye'\n  end\nend\n```\n\nThe `Abroad.extractor` method returns a registered extractor class, or `nil` if the extractor can't be found. Extractor classes respond to `open`, `from_stream`, and `from_string`, and can be called with or without a block. If passed a block, the file or stream will be automatically closed when the block terminates. If you choose to not pass a block, you're responsible for calling `close` yourself.\n\nHere's an example with all the steps broken down:\n\n```ruby\nextractor_klass = Abroad.extractor('yaml/rails')\nextractor = extractor_klass.open('/path/to/en.yml')\nextractor.extract_each do |key, string|\n  ...\nend\nextractor.close\n```\n\nThe `extract_each` method on extractor instances returns an enumerable, which means you have access to all the wonderful `Enumerable` methods like `map`, `inject`, etc:\n\n```ruby\nAbroad.extractor('yaml/rails').open('/path/to/en.yml') do |extractor|\n  extractor.extract_each.with_object({}) do |(key, string), result|\n    result[key] = string\n  end\nend\n```\n\nTo get a list of all available extractors, use the `extractors` method:\n\n```ruby\nAbroad.extractors  # =\u003e [\"yaml/rails\", \"xml/android\", ...]\n```\n\n### Serializers\n\nWhile extractors pull strings out of localization files, serializers write them back in. Serializers conform to a similar interface, but offer different methods to write content out to the stream:\n\n```ruby\nAbroad.serializer('yaml/rails').open('/path/to/es.yml', :es) do |serializer|\n  serializer.write_key_value('welcome.message', 'hola')\n  serializer.write_key_value('goodbye.message', 'adios')\nend\n```\n\nIn addition to `write_key_value`, serializer instances respond to the `write_raw` method, which is capable of writing raw text to the underlying stream. You might use this method if you needed to write a comment to the file or maybe a preamble at the beginning.\n\nSerializer classes respond to `from_stream` in addition to `open`. Both methods can be called with or without a block. If passed a block, the file or stream will be automatically closed when the block terminates. If you choose to not pass a block, you're responsible for calling `close` yourself.\n\nHere's an example with all the steps broken down:\n\n```ruby\nserializer_klass = Abroad.serializer('yaml/rails')\nserializer = serializer_klass.open('/path/to/es.yml', :es)\nserializer.write_key_value('welcome.message', 'hola')\nserializer.write_key_value('goodbye.message', 'adios')\nserializer.close\n```\n\nTo get a list of all available serializers, use the `serializers` method:\n\n```ruby\nAbroad.serializers  # =\u003e [\"yaml/rails\", \"xml/android\", ...]\n```\n\n### Writing Your Own\n\nConformant _extractors_ should inherit from `Abroad::Extractors::Extractor` and need to define the method `extract_each`. See lib/abroad/extractors/extractor.rb for a quick look at the interface. Methods that raise `NotImplementedError`s are ones you need to define in your subclass.\n\nConformant _serializers_ should inherit from `Abroad::Serializers::Serializer` and need to define the `write_key_value` and `write_raw` methods. See lib/abroad/serializers/serializer.rb for a quick look at the interface. Methods that raise `NotImplementedError`s are ones you need to define in your subclass.\n\nOnce you've finished writing your extractor or serializer, register it with Abroad:\n\n```ruby\nAbroad::Extractors.register('strings/ios', Strings::IosExtractor)\nAbroad::Serializers.register('strings/ios', Strings::IosSerializer)\n```\n\nThe first argument to the `register` method is called the serializer or extractor's _id_. The id can really be anything you want, but Abroad has established a convention of format/framework. The format is the underlying file format (eg. json, yaml, xml, etc), and the framework is the platform or application framework you're targeting (eg. iOS, Android, Rails, Django, etc). This makes it easy to avoid writing \"one size fits all\" classes. For example, it would be straightforward to add support for Chrome's localization file format, which is just json with a special structure. We might register an extractor with the id json/chrome instead of trying to retrofit our existing json extractor with Chrome-specific functionality.\n\n## Requirements\n\nThis project has no external requirements.\n\n## Running Tests\n\n`bundle exec rake` or `bundle exec rspec` should do the trick.\n\n## Authors\n\n* Cameron C. Dutro: http://github.com/camertron\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcamertron%2Fabroad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcamertron%2Fabroad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcamertron%2Fabroad/lists"}