{"id":19010304,"url":"https://github.com/railsware/i18n_template","last_synced_at":"2026-04-08T14:02:10.650Z","repository":{"id":1954004,"uuid":"2884142","full_name":"railsware/i18n_template","owner":"railsware","description":"18nTemplate is made to extract phrases and translate html/xhtml/xml document or erb templates","archived":false,"fork":false,"pushed_at":"2012-05-25T12:48:11.000Z","size":160,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":60,"default_branch":"master","last_synced_at":"2026-03-27T10:05:48.445Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/railsware.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2011-11-30T15:35:07.000Z","updated_at":"2019-08-13T14:53:30.000Z","dependencies_parsed_at":"2022-08-20T11:30:50.618Z","dependency_job_id":null,"html_url":"https://github.com/railsware/i18n_template","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/railsware/i18n_template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsware%2Fi18n_template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsware%2Fi18n_template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsware%2Fi18n_template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsware%2Fi18n_template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/railsware","download_url":"https://codeload.github.com/railsware/i18n_template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsware%2Fi18n_template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31558386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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-08T19:10:47.924Z","updated_at":"2026-04-08T14:02:10.623Z","avatar_url":"https://github.com/railsware.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# I18nTemplate\n\n## Main Feature\n\nJust compare regulare rails view internationalization:\n\n    \u003chtml\u003e\n      \u003cbody\u003e\n        \u003c% current_year = Time.now.year %\u003e\n        \u003cspan\u003e\u003c%= t('hello') %\u003e\u003c/span\u003e\n        \u003ch2\u003e\u003c%= t('Dashboard') \u003c/h2\u003e\n        \u003cdiv\u003e\u003c%= t('Posts count:') %\u003e\u003c%= current_user.posts.count %\u003e\u003c/div\u003e\n        \u003cdiv\u003e\u003c%= t('Click') %\u003e\u003ca href=\"#\"\u003e\u003c%= t('here') %\u003e\u003c/a\u003e\u003c/div\u003e\n        ...\n      \u003c/body\u003e\n    \u003c/html\u003e\n\nwith i18n template internationalization:\n\n    \u003chtml\u003e\n      \u003cbody\u003e\n        \u003c% current_year = Time.now.year %\u003e\n        \u003cspan i18n=\"p\"\u003ehello\u003c/span\u003e\n        \u003ch2\u003eDashboard\u003c/h2\u003e\n        \u003cdiv\u003ePosts count: \u003c%= current_user.posts.count %\u003e\u003c/div\u003e\n        \u003cdiv\u003eClick\u003ca href=\"#\"\u003ehere\u003c/a\u003e\u003c/div\u003e\n        ...\n      \u003c/body\u003e\n    \u003c/html\u003e\n\nNice?\n\n## How it Works\n\nIt convert *on the fly* regular erb template to another erb template. For above example this is something like:\n\n    \u003chtml\u003e\n      \u003cbody\u003e\n        \u003c% current_year = Time.now.year %\u003e\n        \u003cspan\u003e\n          \u003c%- i18n_variables = {}; i18n_wrappers = [] -%\u003e\n          \u003c%= ::I18nTemplate::Translation.translate(\"hello\", i18n_wrappers, i18n_variables) %\u003e\n        \u003c/span\u003e\n        \u003ch2\u003e\n          \u003c%- i18n_variables = {}; i18n_wrappers = [] -%\u003e\n          \u003c%= ::I18nTemplate::Translation.translate(\"Dashboard\", i18n_wrappers, i18n_variables) %\u003e\n         \u003c/h2\u003e\n        \u003cdiv\u003e\n          \u003c%- i18n_variables = {}; i18n_wrappers = [] -%\u003e\n          \u003c%- i18n_variables['current user posts count'] = capture do -%\u003e\n            \u003c%= current_user.posts.count %\u003e\n          \u003c%- end -%\u003e\n          \u003c%= ::I18nTemplate::Translation.translate(\"Posts count: {current user posts count}\",\n              i18n_wrappers, i18n_variables) %\u003e\n        \u003c/div\u003e\n        \u003cdiv\u003e\n          \u003c%- i18n_variables = {}; i18n_wrappers = [] -%\u003e\n          \u003c%- i18n_wrappers[1] = capture do -%\u003e\n            \u003ca href=\"#\" i18n_wrapper=\"1\"\u003e\n              \u003c%- i18n_variables = {}; i18n_wrappers = [] -%\u003e\n              \u003c%= ::I18nTemplate::Translation.translate(\"here\", i18n_wrappers, i18n_variables) %\u003e\n            \u003c/a\u003e\n          \u003c%- end -%\u003e\n          \u003c%= ::I18nTemplate::Translation.translate(\"Click[1]here[/1]\", i18n_wrappers, i18n_variables) %\u003e\n         \u003c/div\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n\nTranslation phrases (keys):\n\n* _hello_\n* _Dashboard_\n* _Posts count: {current user posts count}_\n* _Click[1]here[/1]_\n\n## Description\n\nI18nTemplate is made to extract phrases and translate html/xhtml/xml document or erb templates.\nCurrently the it can work with (x)html documents.\nTranslation is done by modify the original template (on the fly) to be translated on erb execution time.\n\n## Semantics\n\nThe engine is leveraging the HTML document semantics.\nAs we know HTML document element can contain : block elements and/or inline elements.\nThe engine has the following parsing rules, based on what kind of children a parent element contains:\n\n* block element containing only block elements - is named a parent element, and is ignored by the engine;\n* block element containing only inline elements - is named phrase, while every inline element is named a word;\n* inline element containing other inline elements - is also a word;\n* any other variation - is considered a broken element, which should be one of there above.\n\n### Markup\n\nAdditionally for the sake of best practices and optimiztion the following rules take place:\n\n* the following elements as considered block elements by the engine \n * usual block : `blockquote p div h1 h2 h3 h4 h5 h6 li dd dt`\n * inline elements : `td th a legend label title caption option optgroup button`\n* the following elements, and their content, will be ignored by the engine:\n * html elements: `select style script` \n * non-breaking space: `\u0026nbsp;` \n * erb scriptlets: `\u003c% \u003c%=`\n * html comments: `\u003c!-- --\u003e`\n * xhtml doctype: `\u003c!DOCTYPE`\n* additional best practices are added to translate content inside such tags\n\nIn order to fix a broken elements next elements/attributes can be added to the html document to resolve engine misunderstanding:\n\n* `\u003ci18n\u003econtent\u003c/i18n\u003e` - mark invisible for parser content for internationalization\n* `\u003c... i18n=\"i\" ...\u003econtent\u003c...\u003e`  - (ignore) ignore element content internationalization\n* `\u003c... i18n=\"p\" ...\u003econtent\u003c...\u003e`  - (phrase) explicitly enable content internationalization\n* `\u003c... i18n=\"s\" ...\u003econtent\u003c...\u003e`  - (subphrase) mark element content as sub-phrase for parent element phrase\n\n## Translation\n\n### Brackets\n\n    [1]Hello World[/1]\n\n### Braces\n\nExample\n\n    Hello { user name }\n\n* `\u003c%= @user_name %\u003e`  as `{user name}`\n* `\u003c%= user_name %\u003e`  as `{user name}`\n* `\u003c%= @post.comments.count %\u003e`  as `{post comments count}`\n\n## Using with Rails (2.3.x 3.x.x)\n\n    $ gem install i18n_template\n\n    require 'i18n_template'\n\n    ActionView::Template.register_template_handler(:erb, I18nTemplate::Handler.new)\n\n### Set another phrase translator:\n\n    I18nTemplate.phrase_translator = lambda { |phrase| Google.translate(phrase) }\n\n### More template internationalize control\n\nAssume we don't want to internationalize admin view templates.\n\n    class MyI18nTemplateHandler \u003c I18nTemplate::Handler\n      def internationalize?(template)\n        if template.respond_to?(:path)\n          path =~ /^admin/ ? false : true\n        else\n          true\n        end\n      end\n    end\n\n    ActionView::Template.register_template_handler(:erb, MyI18nTemplateHandler.new)\n\n## Testing\n\n### Setup\n\n    $ rvm alias create rails23_r187 ruby-1.8.7\n    $ rvm alias create rails30_r193 ruby-1.9.3\n    $ rvm alias create rails31_r193 ruby-1.9.3\n\n    $ gem install multiversion\n    $ multiversion all bundle install\n\n### Run\n\nAgainst all versions:\n\n    $ multiversion all exec testrb test/*_test.rb\n\nAgainst specific versions:\n\n    $ multiversion rails30_r193,rails31_r193 exec testrb test/*_test.rb\n\n\n## Extract phrases\n\n    $ i18n_template --help\n    extract_phrases - extract phrases for translations\n        --format plain|gettext|yaml  translation format (default gettext)\n        --po-root PO ROOT            root directly for po files (default po)\n        --glob GLOB                  template files glob (default app/views/**/*.{erb,rhtml})\n        --textdomain TEXTDOMAIN      gettext textdomain (default phrases)\n        --output-file FILE           output file (default template_phrases.txt)\n        --locales-root DIRECTORY     locales directory (default config/locales)\n\n### Plain format\n\n    $ i18n_template extract_phrases --format plain --output-file /tmp/phrases.txt\n\n### Yaml format\n\n    $ i18n_template extract_phrases --format yaml\n\n    $ cat config/locales/phrases.yml\n    en:\n      Hello {user name}, {message}: \n      '[1]First name[/1] : {profile first name}': \n      '[1]Last name[/1] : {profile last name}': \n      '[1]Email[/1] : {account email}': \n      Copyright {current year}. All rights reserved.: \n\n### Gettext format\n\n    $ i18n_template extract_phrases \\\n      --textdomain myapp \\\n      --glob app/views/**/*.erb \\\n      --glob lib/view/**/*.erb\n\n    $ tree --dirsfirst po\n    po\n    ├── de\n    │   └── myapp.po\n    └── myapp.pot\n\n    $ cat po/phrases.pot\n    # SOME DESCRIPTIVE TITLE.\n    # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n    # This file is distributed under the same license as the PACKAGE package.\n    # FIRST AUTHOR \u003cEMAIL@ADDRESS\u003e, YEAR.\n    #\n    msgid \"\"\n    msgstr \"\"\n    \"Project-Id-Version: PACKAGE VERSION\\n\"\n    \"POT-Creation-Date: 2011-11-28 15:38+0200\\n\"\n    \"PO-Revision-Date: 2011-11-25 21:27+0200\\n\"\n    \"Last-Translator: FULL NAME \u003cEMAIL@ADDRESS\u003e\\n\"\n    \"Language-Team: LANGUAGE \u003cLL@li.org\u003e\\n\"\n    \"Language: \\n\"\n    \"MIME-Version: 1.0\\n\"\n    \"Content-Type: text/plain; charset=UTF-8\\n\"\n    \"Content-Transfer-Encoding: 8bit\\n\"\n    \"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n    # app/views/_footer.html.erb\n    msgid \"Copyright {current year}. All rights reserved.\"\n    msgstr \"\"\n\n    # app/views/greeting.html.erb\n    msgid \"Hello {user name}, {message}\"\n    msgstr \"\"\n\n## References\n\n* [i18n_template rubydocs](http://rubydoc.info/github/railsware/i18n_template/master/frames)\n* [multiversion](https://github.com/railsware/multiversion)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frailsware%2Fi18n_template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frailsware%2Fi18n_template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frailsware%2Fi18n_template/lists"}