├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.rdoc ├── Rakefile ├── app ├── assets │ └── javascripts │ │ └── jquery.autosize-min.js ├── backends │ └── translator │ │ ├── mongo_store.rb │ │ └── redis_store.rb ├── controllers │ └── translator │ │ └── translations_controller.rb └── views │ ├── layouts │ └── translator.html.erb │ └── translator │ └── translations │ ├── _form.html.erb │ ├── create.js.erb │ ├── destroy.js.erb │ └── index.html.erb ├── config └── routes.rb ├── lib ├── translator.rb └── translator │ └── engine.rb ├── spec ├── acceptance │ ├── acceptance_helper.rb │ ├── mongodb_spec.rb │ ├── redis_spec.rb │ ├── support │ │ └── helpers.rb │ └── translations_management.rb ├── controllers │ └── translations_controller_spec.rb ├── dummy │ ├── Rakefile │ ├── app │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── welcome_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ └── views │ │ │ ├── layouts │ │ │ ├── application.html.erb │ │ │ └── dummy_admin.html.erb │ │ │ └── welcome │ │ │ └── index.html.erb │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── backtrace_silencers.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ └── translator.rb │ │ ├── locales │ │ │ ├── de.yml │ │ │ ├── en.yml │ │ │ └── pl.yml │ │ └── routes.rb │ ├── log │ │ ├── production.log │ │ └── server.log │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── favicon.ico │ │ ├── javascripts │ │ │ ├── application.js │ │ │ ├── controls.js │ │ │ ├── dragdrop.js │ │ │ ├── effects.js │ │ │ ├── prototype.js │ │ │ └── rails.js │ │ └── stylesheets │ │ │ └── .gitkeep │ └── script │ │ └── rails ├── spec_helper.rb └── unit │ ├── mongo_store_spec.rb │ ├── redis_store_spec.rb │ └── translator_spec.rb └── translator.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | spec/dummy/db/*.sqlite3 5 | spec/dummy/log/*.log 6 | spec/dummy/tmp/ 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gem "rails", "3.2.7" 4 | gem 'i18n', '0.6.11' 5 | gem 'yajl-ruby', require: 'yajl/json_gem' 6 | gem "mongo", "1.1" 7 | gem "bson_ext", ">=1.0.5" 8 | gem "redis" 9 | 10 | if RUBY_VERSION < '1.9' 11 | gem "ruby-debug", ">= 0.10.3" 12 | end 13 | 14 | gem "diff-lcs", "1.1.3", :require => nil 15 | gem "rspec-rails", '>= 2.10.1' 16 | 17 | gem "capybara", "1.1.2", :require => nil 18 | gem 'selenium-webdriver' 19 | gem "timecop", "0.3.5" 20 | gem "cgi_multipart_eof_fix" 21 | gem "fastthread" 22 | gem "pry" 23 | 24 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.7) 5 | actionpack (= 3.2.7) 6 | mail (~> 2.4.4) 7 | actionpack (3.2.7) 8 | activemodel (= 3.2.7) 9 | activesupport (= 3.2.7) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.0) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.1.3) 17 | activemodel (3.2.7) 18 | activesupport (= 3.2.7) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.7) 21 | activemodel (= 3.2.7) 22 | activesupport (= 3.2.7) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.7) 26 | activemodel (= 3.2.7) 27 | activesupport (= 3.2.7) 28 | activesupport (3.2.7) 29 | i18n (~> 0.6) 30 | multi_json (~> 1.0) 31 | arel (3.0.2) 32 | bson (1.2.4) 33 | bson_ext (1.2.4) 34 | builder (3.0.3) 35 | capybara (1.1.2) 36 | mime-types (>= 1.16) 37 | nokogiri (>= 1.3.3) 38 | rack (>= 1.0.0) 39 | rack-test (>= 0.5.4) 40 | selenium-webdriver (~> 2.0) 41 | xpath (~> 0.1.4) 42 | cgi_multipart_eof_fix (2.5.0) 43 | childprocess (0.5.3) 44 | ffi (~> 1.0, >= 1.0.11) 45 | coderay (1.0.8) 46 | diff-lcs (1.1.3) 47 | erubis (2.7.0) 48 | fastthread (1.0.7) 49 | ffi (1.9.3) 50 | hike (1.2.1) 51 | i18n (0.6.11) 52 | journey (1.0.4) 53 | json (1.7.5) 54 | mail (2.4.4) 55 | i18n (>= 0.4.0) 56 | mime-types (~> 1.16) 57 | treetop (~> 1.4.8) 58 | method_source (0.8) 59 | mime-types (1.19) 60 | mongo (1.1) 61 | bson (>= 1.0.5) 62 | multi_json (1.10.1) 63 | nokogiri (1.5.5) 64 | polyglot (0.3.3) 65 | pry (0.9.10) 66 | coderay (~> 1.0.5) 67 | method_source (~> 0.8) 68 | slop (~> 3.3.1) 69 | rack (1.4.1) 70 | rack-cache (1.2) 71 | rack (>= 0.4) 72 | rack-ssl (1.3.2) 73 | rack 74 | rack-test (0.6.2) 75 | rack (>= 1.0) 76 | rails (3.2.7) 77 | actionmailer (= 3.2.7) 78 | actionpack (= 3.2.7) 79 | activerecord (= 3.2.7) 80 | activeresource (= 3.2.7) 81 | activesupport (= 3.2.7) 82 | bundler (~> 1.0) 83 | railties (= 3.2.7) 84 | railties (3.2.7) 85 | actionpack (= 3.2.7) 86 | activesupport (= 3.2.7) 87 | rack-ssl (~> 1.3.2) 88 | rake (>= 0.8.7) 89 | rdoc (~> 3.4) 90 | thor (>= 0.14.6, < 2.0) 91 | rake (0.9.2.2) 92 | rdoc (3.12) 93 | json (~> 1.4) 94 | redis (2.1.1) 95 | rspec (2.11.0) 96 | rspec-core (~> 2.11.0) 97 | rspec-expectations (~> 2.11.0) 98 | rspec-mocks (~> 2.11.0) 99 | rspec-core (2.11.1) 100 | rspec-expectations (2.11.3) 101 | diff-lcs (~> 1.1.3) 102 | rspec-mocks (2.11.3) 103 | rspec-rails (2.11.0) 104 | actionpack (>= 3.0) 105 | activesupport (>= 3.0) 106 | railties (>= 3.0) 107 | rspec (~> 2.11.0) 108 | rubyzip (1.1.6) 109 | selenium-webdriver (2.42.0) 110 | childprocess (>= 0.5.0) 111 | multi_json (~> 1.0) 112 | rubyzip (~> 1.0) 113 | websocket (~> 1.0.4) 114 | slop (3.3.3) 115 | sprockets (2.1.3) 116 | hike (~> 1.2) 117 | rack (~> 1.0) 118 | tilt (~> 1.1, != 1.3.0) 119 | thor (0.16.0) 120 | tilt (1.3.3) 121 | timecop (0.3.5) 122 | treetop (1.4.11) 123 | polyglot 124 | polyglot (>= 0.3.1) 125 | tzinfo (0.3.33) 126 | websocket (1.0.7) 127 | xpath (0.1.4) 128 | nokogiri (~> 1.3) 129 | yajl-ruby (1.1.0) 130 | 131 | PLATFORMS 132 | ruby 133 | 134 | DEPENDENCIES 135 | bson_ext (>= 1.0.5) 136 | capybara (= 1.1.2) 137 | cgi_multipart_eof_fix 138 | diff-lcs (= 1.1.3) 139 | fastthread 140 | i18n (= 0.6.11) 141 | mongo (= 1.1) 142 | pry 143 | rails (= 3.2.7) 144 | redis 145 | rspec-rails (>= 2.10.1) 146 | selenium-webdriver 147 | timecop (= 0.3.5) 148 | yajl-ruby 149 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 YOURNAME 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = Translator 2 | 3 | == Installation 4 | 5 | === For MongoDB: 6 | 7 | Create Gemfile and run "bundle": 8 | 9 | gem 'mongo' 10 | gem 'bson_ext' 11 | gem 'translator', :git => "git://github.com/amberbit/translator.git" 12 | 13 | Create initializer, for example config/initializers/translator.rb: 14 | conn = Mongo::Connection.new.db("translator_test").collection("translations") 15 | Translator.current_store = Translator::MongoStore.new(conn) 16 | I18n.backend = Translator.setup_backend(I18n::Backend::Simple.new) 17 | 18 | In Rails > 3.2 you should mount the translator Engine in config/routes.rb: 19 | mount Translator::Engine => '/admin' # will provide a /admin/translations path 20 | 21 | You might also need to override default yaml parser by adding the line to Gemfile: 22 | gem 'yajl-ruby', require: 'yajl/json_gem' 23 | 24 | There also appear to be problems with i18n v0.6.1 (truncated translations), so you might need to force v0.6.0: 25 | gem 'i18n', '0.6.0' 26 | 27 | === For Redis: 28 | 29 | Create Gemfile and run "bundle": 30 | 31 | gem 'redis' 32 | gem 'translator', :git => "git://github.com/amberbit/translator.git" 33 | 34 | Create initializer, for example config/initializers/translator.rb: 35 | 36 | Translator.current_store = Translator::RedisStore.new(Redis.new) 37 | I18n.backend = Translator.setup_backend(I18n::Backend::Simple.new) 38 | 39 | == Usage 40 | 41 | Remember to restart your server after running 'bundle' command. Translations engine is available under http://localhost:3000/translations and there is *no authorization* by default. 42 | 43 | Default values for your translations will be loaded from config/locales/*.yml and you can revert back to using them by clicking "Default" link next to translations you make. 44 | 45 | === Adding authorization 46 | 47 | You can add custom authorization procedure, that will be executed in 48 | context of translations controller. Just append some code to your 49 | initializer. 50 | 51 | For simple HTTP Basic authorization, you could use the following: 52 | 53 | Translator.auth_handler = proc { 54 | authenticate_or_request_with_http_basic do |user_name, password| 55 | user_name == 'some' && password == 'user' 56 | end 57 | } 58 | 59 | Or to use with Devise and some RBAC: 60 | 61 | Translator.auth_handler = proc { 62 | unless current_user && current_user.roles.include?(Role.find_by_name("admin")) 63 | redirect_to new_user_session_path 64 | end 65 | } 66 | 67 | === Custom layout 68 | 69 | You can use custom layout if you want. Remember to include jQuery with 70 | Rails' UJS bindings to it, otherwise 'Default' link will not work, but 71 | you will be able to perform translations. 72 | 73 | To use custom layout file ("admin.html.erb" in this example), append the following code to initializer: 74 | 75 | Translator.layout_name = "admin" 76 | 77 | === Adding extra 'Framework Translations' 78 | 79 | Framework translations tab by default includes all Rails translations, 80 | skipping ActiveRecord and ActionMailer ones. Minimal approach here. But 81 | you can mark whichever keys you want as 'Framework Translations'. Here's 82 | the example that you could use with Spree: 83 | 84 | spree_keys = ["activerecord.errors.messages.invalid", "activerecord.errors.messages.invalid_event", "activerecord.errors.messages.invalid_transition", "activerecord.errors.messages.taken", "activerecord.errors.messages.record_invalid", "activerecord.attributes.address.address1", "activerecord.attributes.address.address2", "activerecord.attributes.address.city", "activerecord.attributes.address.country", "activerecord.attributes.address.first_name", "activerecord.attributes.address.first_name_begins_with", "activerecord.attributes.address.last_name", "activerecord.attributes.address.last_name_begins_with", "activerecord.attributes.address.phone", "activerecord.attributes.address.state", "activerecord.attributes.address.zipcode", "activerecord.attributes.checkout.bill_address.address1", "activerecord.attributes.checkout.bill_address.city", "activerecord.attributes.checkout.bill_address.firstname", "activerecord.attributes.checkout.bill_address.lastname", "activerecord.attributes.checkout.bill_address.phone", "activerecord.attributes.checkout.bill_address.state", "activerecord.attributes.checkout.bill_address.zipcode", "activerecord.attributes.checkout.ship_address.address1", "activerecord.attributes.checkout.ship_address.city", "activerecord.attributes.checkout.ship_address.firstname", "activerecord.attributes.checkout.ship_address.lastname", "activerecord.attributes.checkout.ship_address.phone", "activerecord.attributes.checkout.ship_address.state", "activerecord.attributes.checkout.ship_address.zipcode", "activerecord.attributes.country.iso", "activerecord.attributes.country.iso3", "activerecord.attributes.country.iso_name", "activerecord.attributes.country.name", "activerecord.attributes.country.numcode", "activerecord.attributes.creditcard.cc_type", "activerecord.attributes.creditcard.month", "activerecord.attributes.creditcard.number", "activerecord.attributes.creditcard.verification_value", "activerecord.attributes.creditcard.year", "activerecord.attributes.inventory_unit.state", "activerecord.attributes.line_item.price", "activerecord.attributes.line_item.quantity", "activerecord.attributes.order.checkout_complete", "activerecord.attributes.order.ip_address", "activerecord.attributes.order.item_total", "activerecord.attributes.order.number", "activerecord.attributes.order.special_instructions", "activerecord.attributes.order.state", "activerecord.attributes.order.total", "activerecord.attributes.product.available_on", "activerecord.attributes.product.cost_price", "activerecord.attributes.product.description", "activerecord.attributes.product.master_price", "activerecord.attributes.product.name", "activerecord.attributes.product.on_hand", "activerecord.attributes.product.shipping_category", "activerecord.attributes.product.tax_category", "activerecord.attributes.product_group.name", "activerecord.attributes.product_group.product_count", "activerecord.attributes.product_group.product_scopes", "activerecord.attributes.product_group.products", "activerecord.attributes.product_group.url", "activerecord.attributes.product_scope.arguments", "activerecord.attributes.product_scope.description", "activerecord.attributes.property.name", "activerecord.attributes.property.presentation", "activerecord.attributes.prototype.name", "activerecord.attributes.return_authorization.amount", "activerecord.attributes.role.name", "activerecord.attributes.state.abbr", "activerecord.attributes.state.name", "activerecord.attributes.tax_category.description", "activerecord.attributes.tax_category.name", "activerecord.attributes.tax_rate.amount", "activerecord.attributes.taxon.name", "activerecord.attributes.taxon.permalink", "activerecord.attributes.taxon.position", "activerecord.attributes.taxonomy.name", "activerecord.attributes.user.email", "activerecord.attributes.variant.cost_price", "activerecord.attributes.variant.depth", "activerecord.attributes.variant.height", "activerecord.attributes.variant.price", "activerecord.attributes.variant.sku", "activerecord.attributes.variant.weight", "activerecord.attributes.variant.width", "activerecord.attributes.zone.description", "activerecord.attributes.zone.name", "activerecord.models.address.one", "activerecord.models.address.other", "activerecord.models.cheque_payment.one", "activerecord.models.cheque_payment.other", "activerecord.models.country.one", "activerecord.models.country.other", "activerecord.models.creditcard.one", "activerecord.models.creditcard.other", "activerecord.models.creditcard_payment.one", "activerecord.models.creditcard_payment.other", "activerecord.models.creditcard_txn.one", "activerecord.models.creditcard_txn.other", "activerecord.models.inventory_unit.one", "activerecord.models.inventory_unit.other", "activerecord.models.line_item.one", "activerecord.models.line_item.other", "activerecord.models.order.one", "activerecord.models.order.other", "activerecord.models.payment.one", "activerecord.models.payment.other", "activerecord.models.product.one", "activerecord.models.product.other", "activerecord.models.product_group.one", "activerecord.models.product_group.other", "activerecord.models.property.one", "activerecord.models.property.other", "activerecord.models.prototype.one", "activerecord.models.prototype.other", "activerecord.models.return_authorization.one", "activerecord.models.return_authorization.other", "activerecord.models.role.one", "activerecord.models.role.other", "activerecord.models.shipment.one", "activerecord.models.shipment.other", "activerecord.models.shipping_category.one", "activerecord.models.shipping_category.other", "activerecord.models.state.one", "activerecord.models.state.other", "activerecord.models.tax_category.one", "activerecord.models.tax_category.other", "activerecord.models.tax_rate.one", "activerecord.models.tax_rate.other", "activerecord.models.taxon.one", "activerecord.models.taxon.other", "activerecord.models.taxonomy.one", "activerecord.models.taxonomy.other", "activerecord.models.user.one", "activerecord.models.user.other", "activerecord.models.variant.one", "activerecord.models.variant.other", "activerecord.models.zone.one", "activerecord.models.zone.other", "errors.messages.not_found", "errors.messages.already_confirmed", "errors.messages.not_locked", "errors.messages.not_saved.one", "errors.messages.not_saved.other", "no", "yes", "5_biggest_spenders", "a_copy_of_all_mail_will_be_sent_to_the_following_addresses", "abbreviation", "access_denied", "account", "account_updated", "action", "actions.cancel", "actions.create", "actions.destroy", "actions.list", "actions.listing", "actions.new", "actions.update", "active", "add", "add_category", "add_country", "add_option_type", "add_option_types", "add_option_value", "add_product", "add_product_properties", "add_scope", "add_state", "add_to_cart", "add_zone", "additional_item", "address", "address_information", "adjustment", "adjustment_total", "adjustments", "administration", "all", "all_departments", "allow_backorders", "allow_ssl_to_be_used_when_in_developement_and_test_modes", "allow_ssl_to_be_used_when_in_production_mode", "allowed_ssl_in_production_mode", "already_registered", "alt_text", "alternative_phone", "amount", "analytics_trackers", "apply", "are_you_sure", "are_you_sure_category", "are_you_sure_delete", "are_you_sure_delete_image", "are_you_sure_option_type", "are_you_sure_you_want_to_capture", "assign_taxon", "assign_taxons", "authorization_failure", "authorized", "available_on", "available_taxons", "awaiting_return", "back", "back_end", "back_to_store", "backordered", "backordering_is_allowed", "balance_due", "best_selling_products", "best_selling_taxons", "bill_address", "billing", "billing_address", "both", "by_day", "calculator", "calculator_settings_warning", "cancel", "cancel_my_account", "cancel_my_account_description", "canceled", "cannot_create_returns", "cannot_destory_line_item_as_inventory_units_have_shipped", "cannot_perform_operation", "capture", "card_code", "card_details", "card_number", "card_type_is", "cart", "categories", "category", "change", "change_language", "change_my_password", "charge_total", "charged", "charges", "checkout", "cheque", "city", "clone", "code", "combine", "complete", "complete_list", "configuration", "configuration_options", "configurations", "configured", "confirm", "confirm_delete", "confirm_password", "continue", "continue_shopping", "copy_all_mails_to", "cost_price", "count", "count_of_reduced_by", "country", "country_based", "create", "create_a_new_account", "create_product_group_from_products", "create_user_account", "created_successfully", "credit", "credit_card", "credit_card_capture_complete", "credit_card_payment", "credit_owed", "credit_total", "creditcard", "creditcards", "credits", "current", "customer", "customer_details", "customer_search", "date_created", "date_range", "debit", "default", "delete", "depth", "description", "destroy", "didnt_receive_confirmation_instructions", "didnt_receive_unlock_instructions", "discount_amount", "display", "edit", "editing_billing_integration", "editing_category", "editing_mail_method", "editing_option_type", "editing_option_types", "editing_payment_method", "editing_product", "editing_product_group", "editing_property", "editing_prototype", "editing_shipping_category", "editing_shipping_method", "editing_state", "editing_tax_category", "editing_tax_rate", "editing_tracker", "editing_user", "editing_zone", "email", "email_address", "email_server_settings_description", "empty", "empty_cart", "enable_login_via_login_password", "enable_login_via_openid", "enable_mail_delivery", "enter_exactly_as_shown_on_card", "enter_password_to_confirm", "environment", "error", "event", "existing_customer", "expiration", "expiration_month", "expiration_year", "extension", "extensions", "filename", "final_confirmation", "finalize", "finalized_payments", "first_item", "first_name", "first_name_begins_with", "flat_percent", "flat_rate_amount", "flat_rate_per_item", "flat_rate_per_order", "flexible_rate", "forgot_password", "front_end", "full_name", "gateway", "gateway_configuration", "gateway_error", "gateway_setting_description", "gateway_settings_warning", "general", "general_settings", "general_settings_description", "google_analytics", "google_analytics_active", "google_analytics_create", "google_analytics_id", "google_analytics_new", "google_analytics_setting_description", "guest_checkout", "guest_user_account", "has_no_shipped_units", "height", "hello_user", "history", "home", "icon", "icons_by", "image", "images", "images_for", "in_progress", "include_in_shipment", "included_in_other_shipment", "included_in_this_shipment", "instructions_to_reset_password", "integration_settings_warning", "intercept_email_address", "intercept_email_instructions", "invalid_search", "inventory", "inventory_adjustment", "inventory_setting_description", "inventory_settings", "is_not_available_to_shipment_address", "issue_number", "item", "item_description", "item_total", "items", "last_14_days", "last_5_orders", "last_7_days", "last_month", "last_name", "last_name_begins_with", "last_year", "leave_blank_to_not_change", "list", "listing_categories", "listing_option_types", "listing_orders", "listing_product_groups", "listing_reports", "listing_tax_categories", "listing_users", "live", "loading", "locale_changed", "log_in", "logged_in_as", "logged_in_succesfully", "logged_out", "login", "login_as_existing", "login_failed", "login_name", "logout", "look_for_similar_items", "maestro_or_solo_cards", "mail_delivery_enabled", "mail_delivery_not_enabled", "mail_methods", "mail_server_preferences", "make_refund", "mark_shipped", "master_price", "max_items", "meta_description", "meta_keywords", "metadata", "missing_required_information", "minimal_amount", "month", "my_account", "my_orders", "name", "name_or_sku", "new", "new_adjustment", "new_billing_integration", "new_category", "new_customer", "new_image", "new_mail_method", "new_option_type", "new_option_value", "new_order", "new_order_completed", "new_payment", "new_payment_method", "new_product", "new_product_group", "new_property", "new_prototype", "new_return_authorization", "new_shipment", "new_shipping_category", "new_shipping_method", "new_state", "new_tax_category", "new_tax_rate", "new_taxon", "new_taxonomy", "new_tracker", "new_user", "new_variant", "new_zone", "next", "no_items_in_cart", "no_match_found", "no_payment_methods_available", "no_products_found", "no_results", "no_shipping_methods_available", "no_user_found", "none", "none_available", "normal_amount", "not", "not_shown", "note", "notice_messages.option_type_removed", "notice_messages.product_cloned", "notice_messages.product_deleted", "notice_messages.product_not_cloned", "notice_messages.product_not_deleted", "notice_messages.variant_deleted", "notice_messages.variant_not_deleted", "on_hand", "operation", "option_Values", "option_types", "option_values", "options", "or", "ord_qty", "ord_total", "order", "order_confirmation_note", "order_date", "order_details", "order_email_resent", "order_not_in_system", "order_number", "order_operation_authorize", "order_processed_but_following_items_are_out_of_stock", "order_processed_successfully", "order_state.address", "order_state.adjustments", "order_state.awaiting_return", "order_state.canceled", "order_state.cart", "order_state.complete", "order_state.confirm", "order_state.delivery", "order_state.payment", "order_state.resumed", "order_state.returned", "order_summary", "order_sure_want_to", "order_total", "order_total_message", "order_updated", "orders", "other_payment_options", "out_of_stock", "out_of_stock_products", "over_paid", "overview", "overview_welcome", "page_only_viewable_when_logged_in", "page_only_viewable_when_logged_out", "paid", "parent_category", "password", "password_reset_instructions", "password_reset_instructions_are_mailed", "password_reset_token_not_found", "password_updated", "path", "pay", "payment", "payment_gateway", "payment_information", "payment_method", "payment_methods", "payment_methods_setting_description", "payment_processing_failed", "payment_state", "payment_states.balance_due", "payment_states.credit_owed", "payment_states.failed", "payment_states.paid", "payment_updated", "payments", "pending_payments", "permalink", "phone", "place_order", "please_create_user", "powered_by", "presentation", "preview", "previous", "price", "price_bucket", "price_with_vat_included", "problem_authorizing_card", "problem_capturing_card", "problems_processing_order", "proceed_as_guest", "process", "product", "product_details", "product_group", "product_group_invalid", "product_groups", "product_has_no_description", "product_properties", "product_scopes.groups.price.description", "product_scopes.groups.price.name", "product_scopes.groups.search.description", "product_scopes.groups.search.name", "product_scopes.groups.taxon.description", "product_scopes.groups.taxon.name", "product_scopes.groups.values.description", "product_scopes.groups.values.name", "product_scopes.scopes.ascend_by_master_price.name", "product_scopes.scopes.ascend_by_name.name", "product_scopes.scopes.ascend_by_updated_at.name", "product_scopes.scopes.descend_by_master_price.name", "product_scopes.scopes.descend_by_name.name", "product_scopes.scopes.descend_by_popularity.name", "product_scopes.scopes.descend_by_updated_at.name", "product_scopes.scopes.in_name.args.words", "product_scopes.scopes.in_name.description", "product_scopes.scopes.in_name.name", "product_scopes.scopes.in_name.sentence", "product_scopes.scopes.in_name_or_description.args.words", "product_scopes.scopes.in_name_or_description.description", "product_scopes.scopes.in_name_or_description.name", "product_scopes.scopes.in_name_or_description.sentence", "product_scopes.scopes.in_name_or_keywords.args.words", "product_scopes.scopes.in_name_or_keywords.description", "product_scopes.scopes.in_name_or_keywords.name", "product_scopes.scopes.in_name_or_keywords.sentence", "product_scopes.scopes.in_taxons.args.taxon_names", "product_scopes.scopes.in_taxons.description", "product_scopes.scopes.in_taxons.name", "product_scopes.scopes.in_taxons.sentence", "product_scopes.scopes.master_price_gte.args.amount", "product_scopes.scopes.master_price_gte.description", "product_scopes.scopes.master_price_gte.name", "product_scopes.scopes.master_price_gte.sentence", "product_scopes.scopes.master_price_lte.args.amount", "product_scopes.scopes.master_price_lte.description", "product_scopes.scopes.master_price_lte.name", "product_scopes.scopes.master_price_lte.sentence", "product_scopes.scopes.price_between.args.high", "product_scopes.scopes.price_between.args.low", "product_scopes.scopes.price_between.description", "product_scopes.scopes.price_between.name", "product_scopes.scopes.price_between.sentence", "product_scopes.scopes.taxons_name_eq.args.taxon_name", "product_scopes.scopes.taxons_name_eq.description", "product_scopes.scopes.taxons_name_eq.name", "product_scopes.scopes.taxons_name_eq.sentence", "product_scopes.scopes.with.args.value", "product_scopes.scopes.with.description", "product_scopes.scopes.with.name", "product_scopes.scopes.with.sentence", "product_scopes.scopes.with_ids.args.ids", "product_scopes.scopes.with_ids.description", "product_scopes.scopes.with_ids.name", "product_scopes.scopes.with_ids.sentence", "product_scopes.scopes.with_option.args.option", "product_scopes.scopes.with_option.description", "product_scopes.scopes.with_option.name", "product_scopes.scopes.with_option.sentence", "product_scopes.scopes.with_option_value.args.option", "product_scopes.scopes.with_option_value.args.value", "product_scopes.scopes.with_option_value.description", "product_scopes.scopes.with_option_value.name", "product_scopes.scopes.with_option_value.sentence", "product_scopes.scopes.with_property.args.property", "product_scopes.scopes.with_property.description", "product_scopes.scopes.with_property.name", "product_scopes.scopes.with_property.sentence", "product_scopes.scopes.with_property_value.args.property", "product_scopes.scopes.with_property_value.args.value", "product_scopes.scopes.with_property_value.description", "product_scopes.scopes.with_property_value.name", "product_scopes.scopes.with_property_value.sentence", "products", "products_with_zero_inventory_display", "properties", "property", "prototype", "prototypes", "provider", "provider_settings_warning", "qty", "quantity_shipped", "quantity_returned", "range", "rate", "reason", "recalculate_order_total", "receive", "received", "refund", "register", "register_or_guest", "registration.page_title", "registration.DD", "registration.MM", "registration.YYYY", "registration.notices.registration_complete", "registration.notices.access_denied_invalid_token", "remember_me", "remove", "reports", "required_for_solo_and_maestro", "resend", "resend_confirmation_instructions", "resend_unlock_instructions", "reset_password", "resource_controller.member_object_not_found", "resource_controller.successfully_created", "resource_controller.successfully_removed", "resource_controller.successfully_updated", "response_code", "resume", "resumed", "return", "return_authorization", "return_authorization_updated", "return_authorizations", "return_quantity", "returned", "rma_credit", "rma_number", "rma_value", "roles", "sales_tax", "sales_total", "sales_total_for_all_orders", "sales_totals", "sales_totals_description", "save_and_continue", "save_preferences", "scope", "scopes", "search", "search_results", "searching", "secure_connection_type", "secure_creditcard", "select", "select_from_prototype", "select_preferred_shipping_option", "send_copy_of_all_mails_to", "send_copy_of_orders_mails_to", "send_mails_as", "send_me_reset_password_instructions", "send_order_mails_as", "server", "server_error", "settings", "ship", "ship_address", "shipment", "shipment_details", "shipment_number", "shipment_state", "shipment_states.backorder", "shipment_states.partial", "shipment_states.pending", "shipment_states.ready", "shipment_states.shipped", "shipment_updated", "shipments", "shipped", "shipping", "shipping_address", "shipping_categories", "shipping_categories_description", "shipping_category", "shipping_cost", "shipping_error", "shipping_instructions", "shipping_method", "shipping_methods", "shipping_methods_description", "shipping_total", "shop_by_taxonomy", "shopping_cart", "show", "show_active", "show_deleted", "show_incomplete_orders", "show_only_complete_orders", "show_out_of_stock_products", "show_price_inc_vat", "showing_first_n", "sign_up", "site_name", "site_url", "sku", "smtp", "smtp_authentication_type", "smtp_domain", "smtp_mail_host", "smtp_password", "smtp_port", "smtp_send_all_emails_as_from_following_address", "smtp_send_copy_to_this_addresses", "smtp_username", "sold", "sort_ordering", "special_instructions", "spree.date", "spree.time", "spree_gateway_error_flash_for_checkout", "ssl_will_be_used_in_development_and_test_modes", "ssl_will_be_used_in_production_mode", "ssl_will_not_be_used_in_development_and_test_modes", "ssl_will_not_be_used_in_production_mode", "start", "start_date", "state", "state_based", "state_setting_description", "states", "status", "stop", "store", "street_address", "street_address_2", "subtotal", "subtract", "system", "tax", "tax_categories", "tax_categories_setting_description", "tax_category", "tax_rates", "tax_rates_description", "tax_settings", "tax_settings_description", "tax_total", "tax_type", "taxon", "taxon_edit", "taxonomies", "taxonomies_setting_description", "taxonomy_edit", "taxonomy_tree_error", "taxonomy_tree_instruction", "taxons", "test", "test_mode", "thank_you_for_your_order", "this_file_language", "this_month", "this_year", "thumbnail", "to_add_variants_you_must_first_define", "top_grossing_products", "total", "tracking", "transaction", "transactions", "tree", "try_again", "type", "type_to_search", "unable_ship_method", "unable_to_authorize_credit_card", "unable_to_capture_credit_card", "unable_to_connect_to_gateway", "unable_to_save_order", "under_paid", "units", "unrecognized_card_type", "update", "update_password", "updated_successfully", "updating", "usage_limit", "use_as_shipping_address", "use_billing_address", "use_different_shipping_address", "use_new_cc", "user", "user_account", "user_created_successfully", "user_details", "users", "validate_on_profile_create", "validation.cannot_be_less_than_shipped_units", "validation.is_too_large", "validation.must_be_int", "validation.must_be_non_negative", "value", "variants", "vat", "version", "view_shipping_options", "void", "website", "weight", "welcome_to_sample_store", "what_is_a_cvv", "what_is_this", "whats_this", "width", "year", "you_have_been_logged_out", "your_cart_is_empty", "zip", "zone", "zone_based", "zone_setting_description", "zones", "devise.failure.unauthenticated", "devise.failure.unconfirmed", "devise.failure.locked", "devise.failure.invalid", "devise.failure.invalid_token", "devise.failure.timeout", "devise.failure.inactive", "devise.sessions.signed_in", "devise.sessions.signed_out", "devise.passwords.send_instructions", "devise.passwords.updated", "devise.confirmations.send_instructions", "devise.confirmations.confirmed", "devise.registrations.signed_up", "devise.registrations.inactive_signed_up", "devise.registrations.updated", "devise.registrations.destroyed", "devise.unlocks.send_instructions", "devise.unlocks.unlocked", "devise.omniauth_callbacks.success", "devise.omniauth_callbacks.failure", "devise.mailer.confirmation_instructions.subject", "devise.mailer.reset_password_instructions.subject", "devise.mailer.unlock_instructions.subject", "devise.user_password_resets.send_instructions", "devise.user_password_resets.updated", "devise.user_registrations.signed_up", "devise.user_registrations.inactive_signed_up", "devise.user_registrations.updated", "devise.user_registrations.destroyed", "devise.user_registrations.user.sent_confirmation_email_message", "devise.user_sessions.signed_in", "devise.user_sessions.signed_out", "devise.oauth_callbacks.success", "devise.oauth_callbacks.failure", "api.access", "api.clear_key", "api.errors.invalid_event", "api.errors.invalid_event_for_object", "api.errors.missing_event", "api.generate_key", "api.key", "api.regenerate_key", "api.no_key", "api.key_generated", "api.key_cleared", "add_rule_of_type", "coupon", "coupon_code", "editing_promotion", "free_shipping", "new_promotion", "no_rules_added", "promotions", "promotion_form.match_policies.all", "promotion_form.match_policies.any", "promotions_description", "promotion_rule_types.user.name", "promotion_rule_types.user.description", "promotion_rule_types.product.name", "promotion_rule_types.product.description", "promotion_rule_types.item_total.name", "promotion_rule_types.item_total.description", "promotion_rule_types.first_order.name", "promotion_rule_types.first_order.description", "product_rule.choose_products", "product_rule.label", "product_rule.match_any", "product_rule.match_all", "product_rule.product_source.group", "product_rule.product_source.manual", "user_rule.choose_users", "item_total_rule.operators.gt", "item_total_rule.operators.gte", "mailer.confirmation.greeting", "mailer.confirmation.subject", "mailer.confirmation.message", "mailer.confirmation.thanking", "mailer.footer.message", "mailer.footer.unsubscribe"] 85 | Translator.framework_keys = (Translator.framework_keys + spree_keys).uniq 86 | 87 | 88 | = User stories 89 | 90 | == Current features: 91 | 92 | As a user, I want to translate my Rails 3 application to different languages, so that more visitors can use it in their native languages. 93 | 94 | As a developer, I want to specify custom authorization proc, so that I can integrate with my application nicely. 95 | 96 | As a developer, I want to have nice layout for translations module, so I don't have to bother with integrating with my admin panel, and have some JavaScript. 97 | 98 | As a user, I want to have default translations for languages loaded from config/*.yml files, so that I can use translation module with existing applications. 99 | 100 | As a user, I want to have default translations loaded from Rails' built in translation files, so that things like validation errors are present for English language. 101 | 102 | As a user, I want to have all Rails translations hidden in 'Framework Translations', so that user can focus primarily on application-specific strings. 103 | 104 | As a developer, I want to override list of 'Framework Translations' with a custom specified in initializer. 105 | 106 | As a user, I want to revert to default translation, loaded from YAML file, by clicking on 'Default' link. 107 | 108 | Ad a user, I want to choose between Redis and MongoDB for translations storage. 109 | 110 | == Future features: 111 | 112 | As a user, I want to have all strings I enter validated, based on values from *.yml files, so I cannot break the app with malformed translations (ie. with wrong number of parameters). 113 | 114 | As a user, I want to export full translations for given language to *yml file, which is syntax-compatible with Rails' default backend, so that I can move it to the other application or disable translate_yourself completely. 115 | 116 | As a user, I want to import full or partial translations for given language from *yml file, skipping keys that are not present in default language. 117 | 118 | = Thanks 119 | 120 | David Heinemeier Hansson for https://github.com/dhh/tolk, Ryan Bates for I18n::Backend screencast http://railscasts.com/episodes/256-i18n-backends. 121 | 122 | = Copyright and License 123 | 124 | Copyright by Hubert Łępicki, 2010-2011. Find me at hubert.lepicki@amberbit.com. 125 | 126 | This software is licensed under the terms of MIT-LICENSE. 127 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require 'rake' 3 | require 'rake/rdoctask' 4 | require 'rake/gempackagetask' 5 | 6 | require 'rspec/core' 7 | require 'rspec/core/rake_task' 8 | 9 | RSpec::Core::RakeTask.new(:spec) 10 | 11 | task :default => :spec 12 | 13 | Rake::RDocTask.new(:rdoc) do |rdoc| 14 | rdoc.rdoc_dir = 'rdoc' 15 | rdoc.title = 'Translator' 16 | rdoc.options << '--line-numbers' << '--inline-source' 17 | rdoc.rdoc_files.include('README.rdoc') 18 | rdoc.rdoc_files.include('lib/**/*.rb') 19 | end 20 | 21 | spec = eval(File.read("translator.gemspec")) 22 | Rake::GemPackageTask.new(spec) do |pkg| 23 | end 24 | 25 | desc "Install the gem #{spec.name}-#{spec.version}.gem" 26 | task :install do 27 | system("gem install pkg/#{spec.name}-#{spec.version}.gem --no-ri --no-rdoc") 28 | end 29 | -------------------------------------------------------------------------------- /app/assets/javascripts/jquery.autosize-min.js: -------------------------------------------------------------------------------- 1 | // Autosize 1.14 - jQuery plugin for textareas 2 | // (c) 2012 Jack Moore - jacklmoore.com 3 | // license: www.opensource.org/licenses/mit-license.php 4 | (function(e){var t={className:"autosizejs",append:"",callback:!1},n="hidden",r="border-box",i="lineHeight",s='