- <%= f.label :"value_#{@locale.code}", "Translation", class: "sr-only" %>
- <%= f.text_area :"value_#{@locale.code}", row: 3, autofocus: true, placeholder: "Enter your translation", class: "block w-full resize-none border-0 bg-transparent py-1.5 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" %>
+ <%= f.label :"content_#{@locale.code}", "Translation", class: "sr-only" %>
+ <%= f.text_area :"content_#{@locale.code}", row: 3, autofocus: true, placeholder: "Enter your translation", class: "block w-full resize-none border-0 bg-transparent py-1.5 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" %>
diff --git a/config/routes.rb b/config/routes.rb
index c747b7b..be2f01e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -14,7 +14,7 @@
end
end
- resources :translation_keys do
+ resources :text_entries do
resource :translation, only: %i[edit update]
end
end
diff --git a/db/migrate/20240930135507_create_rosetta_text_entries.rb b/db/migrate/20240930135507_create_rosetta_text_entries.rb
new file mode 100644
index 0000000..31f318e
--- /dev/null
+++ b/db/migrate/20240930135507_create_rosetta_text_entries.rb
@@ -0,0 +1,14 @@
+class CreateRosettaTextEntries < ActiveRecord::Migration[7.2]
+ def change
+ create_table :rosetta_text_entries do |t|
+ t.text :content, null: false
+ t.references :locale, null: false
+
+ t.timestamps
+
+ t.index :content
+ t.index [ :locale_id, :content ], unique: true
+ t.foreign_key :rosetta_locales, column: :locale_id
+ end
+ end
+end
diff --git a/db/migrate/20240930135810_update_rosetta_translations.rb b/db/migrate/20240930135810_update_rosetta_translations.rb
new file mode 100644
index 0000000..c4dae85
--- /dev/null
+++ b/db/migrate/20240930135810_update_rosetta_translations.rb
@@ -0,0 +1,20 @@
+class UpdateRosettaTranslations < ActiveRecord::Migration[7.2]
+ def change
+ change_table :rosetta_translations do |t|
+ t.remove :value
+
+ t.references :target_locale, null: false
+ t.references :from, null: false
+ t.references :to, null: false
+
+ t.foreign_key :rosetta_locales, column: :target_locale_id
+ t.foreign_key :rosetta_text_entries, column: :from_id
+ t.foreign_key :rosetta_text_entries, column: :to_id
+
+ t.index [ :target_locale_id, :from_id, :to_id ], name: :rosetta_translations_uniqueness, unique: true
+ end
+
+ remove_reference :rosetta_translations, :translation_key
+ remove_reference :rosetta_translations, :locale
+ end
+end
diff --git a/db/migrate/20241002152043_drop_translation_keys.rb b/db/migrate/20241002152043_drop_translation_keys.rb
new file mode 100644
index 0000000..0d62613
--- /dev/null
+++ b/db/migrate/20241002152043_drop_translation_keys.rb
@@ -0,0 +1,5 @@
+class DropTranslationKeys < ActiveRecord::Migration[7.2]
+ def change
+ drop_table :rosetta_translation_keys
+ end
+end
diff --git a/gemfiles/rails_6_1.gemfile.lock b/gemfiles/rails_6_1.gemfile.lock
index c0009ee..54541bb 100644
--- a/gemfiles/rails_6_1.gemfile.lock
+++ b/gemfiles/rails_6_1.gemfile.lock
@@ -172,7 +172,7 @@ GEM
rubocop-performance (1.22.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
- rubocop-rails (2.26.1)
+ rubocop-rails (2.26.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
@@ -192,7 +192,7 @@ GEM
sprockets (>= 3.0.0)
thor (1.3.2)
timeout (0.4.1)
- turbo-rails (2.0.9)
+ turbo-rails (2.0.10)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
diff --git a/gemfiles/rails_7_0.gemfile.lock b/gemfiles/rails_7_0.gemfile.lock
index 91fc7f3..04b03ff 100644
--- a/gemfiles/rails_7_0.gemfile.lock
+++ b/gemfiles/rails_7_0.gemfile.lock
@@ -178,7 +178,7 @@ GEM
rubocop-performance (1.22.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
- rubocop-rails (2.26.1)
+ rubocop-rails (2.26.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
@@ -198,7 +198,7 @@ GEM
sprockets (>= 3.0.0)
thor (1.3.2)
timeout (0.4.1)
- turbo-rails (2.0.9)
+ turbo-rails (2.0.10)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
diff --git a/gemfiles/rails_7_1.gemfile.lock b/gemfiles/rails_7_1.gemfile.lock
index 370f1eb..ee392e1 100644
--- a/gemfiles/rails_7_1.gemfile.lock
+++ b/gemfiles/rails_7_1.gemfile.lock
@@ -103,7 +103,7 @@ GEM
i18n (1.14.6)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
- irb (1.14.0)
+ irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.2)
@@ -207,7 +207,7 @@ GEM
rubocop-performance (1.22.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
- rubocop-rails (2.26.1)
+ rubocop-rails (2.26.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
@@ -228,13 +228,13 @@ GEM
stringio (3.1.1)
thor (1.3.2)
timeout (0.4.1)
- turbo-rails (2.0.9)
+ turbo-rails (2.0.10)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
- webrick (1.8.1)
+ webrick (1.8.2)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
diff --git a/gemfiles/rails_7_2.gemfile.lock b/gemfiles/rails_7_2.gemfile.lock
index 3549152..8fd90c6 100644
--- a/gemfiles/rails_7_2.gemfile.lock
+++ b/gemfiles/rails_7_2.gemfile.lock
@@ -99,7 +99,7 @@ GEM
i18n (1.14.6)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
- irb (1.14.0)
+ irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.2)
@@ -203,7 +203,7 @@ GEM
rubocop-performance (1.22.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
- rubocop-rails (2.26.1)
+ rubocop-rails (2.26.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
@@ -225,14 +225,14 @@ GEM
stringio (3.1.1)
thor (1.3.2)
timeout (0.4.1)
- turbo-rails (2.0.9)
+ turbo-rails (2.0.10)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
useragent (0.16.10)
- webrick (1.8.1)
+ webrick (1.8.2)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
diff --git a/gemfiles/rails_main.gemfile.lock b/gemfiles/rails_main.gemfile.lock
index a91df2d..3ebe2a5 100644
--- a/gemfiles/rails_main.gemfile.lock
+++ b/gemfiles/rails_main.gemfile.lock
@@ -1,31 +1,31 @@
GIT
remote: https://github.com/rails/rails.git
- revision: fd975a87758713a26abe22ab1c337d4ea24c8899
+ revision: cca4db3db4a3a122ca3d9090f4cfd6754aed6487
branch: main
specs:
- actioncable (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actioncable (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
- actionmailbox (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- activejob (= 8.0.0.alpha)
- activerecord (= 8.0.0.alpha)
- activestorage (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actionmailbox (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ activejob (= 8.0.0.beta1)
+ activerecord (= 8.0.0.beta1)
+ activestorage (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
mail (>= 2.8.0)
- actionmailer (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- actionview (= 8.0.0.alpha)
- activejob (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actionmailer (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ actionview (= 8.0.0.beta1)
+ activejob (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
- actionpack (8.0.0.alpha)
- actionview (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actionpack (8.0.0.beta1)
+ actionview (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@@ -33,35 +33,35 @@ GIT
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
- actiontext (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- activerecord (= 8.0.0.alpha)
- activestorage (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actiontext (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ activerecord (= 8.0.0.beta1)
+ activestorage (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
- actionview (8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ actionview (8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
- activejob (8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ activejob (8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
globalid (>= 0.3.6)
- activemodel (8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
- activerecord (8.0.0.alpha)
- activemodel (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ activemodel (8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
+ activerecord (8.0.0.beta1)
+ activemodel (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
timeout (>= 0.4.0)
- activestorage (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- activejob (= 8.0.0.alpha)
- activerecord (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ activestorage (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ activejob (= 8.0.0.beta1)
+ activerecord (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
marcel (~> 1.0)
- activesupport (8.0.0.alpha)
+ activesupport (8.0.0.beta1)
base64
benchmark (>= 0.3)
bigdecimal
@@ -74,23 +74,23 @@ GIT
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
- rails (8.0.0.alpha)
- actioncable (= 8.0.0.alpha)
- actionmailbox (= 8.0.0.alpha)
- actionmailer (= 8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- actiontext (= 8.0.0.alpha)
- actionview (= 8.0.0.alpha)
- activejob (= 8.0.0.alpha)
- activemodel (= 8.0.0.alpha)
- activerecord (= 8.0.0.alpha)
- activestorage (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ rails (8.0.0.beta1)
+ actioncable (= 8.0.0.beta1)
+ actionmailbox (= 8.0.0.beta1)
+ actionmailer (= 8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ actiontext (= 8.0.0.beta1)
+ actionview (= 8.0.0.beta1)
+ activejob (= 8.0.0.beta1)
+ activemodel (= 8.0.0.beta1)
+ activerecord (= 8.0.0.beta1)
+ activestorage (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
bundler (>= 1.15.0)
- railties (= 8.0.0.alpha)
- railties (8.0.0.alpha)
- actionpack (= 8.0.0.alpha)
- activesupport (= 8.0.0.alpha)
+ railties (= 8.0.0.beta1)
+ railties (8.0.0.beta1)
+ actionpack (= 8.0.0.beta1)
+ activesupport (= 8.0.0.beta1)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
@@ -129,7 +129,7 @@ GEM
i18n (1.14.6)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
- irb (1.14.0)
+ irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.2)
diff --git a/lib/rosetta-rails.rb b/lib/rosetta-rails.rb
index 43d9253..2f4719c 100644
--- a/lib/rosetta-rails.rb
+++ b/lib/rosetta-rails.rb
@@ -34,9 +34,9 @@ def locale_session
Thread.current[:rosetta_locale_session] ||= LocaleSession.new
end
- def translate(key, locale: Rosetta.locale)
+ def translate(content, locale: Rosetta.locale)
store = Store.for_locale(locale)
- store.lookup(key)
+ store.lookup(content)
end
def available_locales
diff --git a/lib/rosetta/store.rb b/lib/rosetta/store.rb
index 5bd459e..8522e80 100644
--- a/lib/rosetta/store.rb
+++ b/lib/rosetta/store.rb
@@ -15,14 +15,14 @@ def initialize(locale)
@cache_expiration_timestamp = @locale.updated_at
end
- def lookup(key_value)
- if translations.has_key?(key_value)
- translations[key_value]
+ def lookup(content)
+ if translations.has_key?(content)
+ translations[content]
else
- TranslationKey.create_later(key_value)
+ TextEntry.create_later(content)
# Set the key in the translations store to locate it
# once only.
- translations[key_value] = nil
+ translations[content] = nil
end
end
@@ -44,13 +44,12 @@ def translations
private
def load_translations
- loaded_translations = Rosetta.with_locale(@locale) do
- TranslationKey
- .with_translation(@locale)
- .map do |translation_key|
- [ translation_key.value, translation_key.public_send(:"#{@locale.code}_translation")&.value ]
- end.to_h
- end
+ loaded_translations = TextEntry
+ .with_translated_version(@locale)
+ .where(locale: Rosetta::Locale.default_locale)
+ .map do |text_entry|
+ [ text_entry.content, text_entry.public_send(:"#{@locale.code}_translated_version")&.content ]
+ end.to_h
Concurrent::Hash.new.merge(loaded_translations)
end
diff --git a/lib/rosetta/translated.rb b/lib/rosetta/translated.rb
index 74340d0..0980da0 100644
--- a/lib/rosetta/translated.rb
+++ b/lib/rosetta/translated.rb
@@ -3,11 +3,12 @@ module Translated
extend ActiveSupport::Concern
included do
- has_many :translations, dependent: :destroy
+ scope :missing_translation, ->(locale) { where.missing(:"#{locale.code}_translation") }
+ scope :with_translated_version, ->(locale) { includes(:"#{locale.code}_translated_version") }
end
class_methods do
- def translated_in_all_locales
+ def translate_in_all_locales
Locale.all.each do |locale|
translated_in(locale)
end
@@ -16,24 +17,22 @@ def translated_in_all_locales
end
def translated_in(locale)
- has_one :"#{locale.code}_translation", -> { where(locale_id: locale.id) }, class_name: "Translation", dependent: :destroy
+ has_one :"#{locale.code}_translation", -> { where(target_locale: locale) }, class_name: "Rosetta::Translation", foreign_key: :from_id, dependent: :destroy
+ has_one :"#{locale.code}_translated_version", through: :"#{locale.code}_translation", source: :to
- scope :with_translation, ->(locale) { includes(:"#{locale.code}_translation") }
- scope :with_missing_translation, ->(locale) { with_translation(locale).where.missing(:"#{locale.code}_translation") }
-
- define_method("value_#{locale.code}") do
+ define_method("content_#{locale.code}") do
if translation_changes[locale.code]
- translation_changes[locale.code].value
+ translation_changes[locale.code].content
else
- public_send(:"#{locale.code}_translation")&.value
+ public_send(:"#{locale.code}_translated_version")&.content
end
end
- define_method("value_#{locale.code}=") do |locale_value|
- translation_changes[locale.code] = if locale_value.blank?
+ define_method("content_#{locale.code}=") do |localized_content|
+ translation_changes[locale.code] = if localized_content.blank?
Rosetta::Translated::Delete.new(self, locale)
else
- Rosetta::Translated::Create.new(self, locale, locale_value)
+ Rosetta::Translated::Create.new(self, locale, localized_content)
end
end
@@ -41,6 +40,10 @@ def translated_in(locale)
end
end
+ def content_in(locale)
+ public_send("content_#{locale.code}")
+ end
+
def translation_changes
@translation_changes ||= {}
end
diff --git a/lib/rosetta/translated/create.rb b/lib/rosetta/translated/create.rb
index fdad08e..4688574 100644
--- a/lib/rosetta/translated/create.rb
+++ b/lib/rosetta/translated/create.rb
@@ -1,20 +1,37 @@
module Rosetta
class Translated::Create
- attr_reader :value
+ attr_reader :content
- def initialize(record, locale, value)
+ def initialize(record, locale, content)
@record = record
@locale = locale
- @value = value
+ @content = content
end
def save
- translation.value = @value
@record.public_send(:"#{@locale.code}_translation=", translation)
end
+ def translated_version
+ @translated_version ||= find_or_build_translated_version
+ end
+
def translation
- @translation ||= @record.public_send(:"build_#{@locale.code}_translation")
+ @record.public_send(:"build_#{@locale.code}_translation", to: translated_version)
+ end
+
+ private
+
+ def find_or_build_translated_version
+ find_translated_version || build_translated_version
+ end
+
+ def find_translated_version
+ TextEntry.find_by(locale: @locale, content: @content)
+ end
+
+ def build_translated_version
+ TextEntry.new(locale: @locale, content: @content)
end
end
end
diff --git a/lib/rosetta/translated/delete.rb b/lib/rosetta/translated/delete.rb
index eb68c9a..265d424 100644
--- a/lib/rosetta/translated/delete.rb
+++ b/lib/rosetta/translated/delete.rb
@@ -1,11 +1,11 @@
module Rosetta
class Translated::Delete
- attr_reader :value
+ attr_reader :content
def initialize(record, locale)
@record = record
@locale = locale
- @value = nil
+ @content = nil
end
def save
diff --git a/test/controllers/rosetta/locales/translations_controller_test.rb b/test/controllers/rosetta/locales/translations_controller_test.rb
index bb1a7c3..9e544ec 100644
--- a/test/controllers/rosetta/locales/translations_controller_test.rb
+++ b/test/controllers/rosetta/locales/translations_controller_test.rb
@@ -6,7 +6,6 @@ class Locales::TranslationsControllerTest < ActionDispatch::IntegrationTest
test "index" do
locale = rosetta_locales(:french)
- key = rosetta_translation_keys(:hello)
get locale_translations_path(locale)
assert_response :success
assert_includes response.body, "hello"
diff --git a/test/controllers/rosetta/translations_controller_test.rb b/test/controllers/rosetta/translations_controller_test.rb
index 6c10992..e327d82 100644
--- a/test/controllers/rosetta/translations_controller_test.rb
+++ b/test/controllers/rosetta/translations_controller_test.rb
@@ -6,45 +6,32 @@ class TranslationsControllerTest < ActionDispatch::IntegrationTest
setup do
@locale = rosetta_locales(:french)
- @key = rosetta_translation_keys(:goodbye)
+ @text_entry = rosetta_text_entries(:goodbye)
end
test "edit" do
- get edit_translation_key_translation_path(@key, locale_id: @locale.id)
+ get edit_text_entry_translation_path(@text_entry, locale_id: @locale.id)
assert_response :success
end
test "add a new translation" do
assert_difference("Translation.count", 1) do
- patch translation_key_translation_path(@key), params: { locale_id: @locale.id, translation_key: { value_fr: "Au revoir" } }
+ patch text_entry_translation_path(@text_entry), params: { locale_id: @locale.id, text_entry: { content_fr: "Au revoir" } }
end
- assert_equal "Au revoir", Translation.last.value
+ assert_equal "Au revoir", @text_entry.content_fr
assert_response :success
- assert_includes response.body, @key.value
- end
-
- test "update an existing translation" do
- Translation.create!(locale: @locale, translation_key: @key, value: "Salut")
-
- assert_no_difference("Translation.count") do
- patch translation_key_translation_path(@key), params: { locale_id: @locale.id, translation_key: { value_fr: "Bonjour" } }
- end
-
- assert_equal "Bonjour", Translation.last.value
- assert_response :success
- assert_includes response.body, @key.value
+ assert_includes response.body, @text_entry.content
end
test "setting a blank value removes the translation" do
- Translation.create!(locale: @locale, translation_key: @key, value: "Salut")
+ @text_entry.update(content_fr: "Au revoir")
assert_difference("Translation.count", -1) do
- patch translation_key_translation_path(@key), params: { locale_id: @locale.id, translation_key: { value_fr: "" } }
+ patch text_entry_translation_path(@text_entry), params: { locale_id: @locale.id, text_entry: { content_fr: "" } }
end
assert_response :success
- assert_includes response.body, @key.value
end
end
end
diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb
index 0237d58..a8f3fa8 100644
--- a/test/dummy/db/schema.rb
+++ b/test/dummy/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2024_09_23_100651) do
+ActiveRecord::Schema.define(version: 2024_10_02_152043) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -24,24 +24,30 @@
t.index ["code"], name: "index_rosetta_locales_on_code", unique: true
end
- create_table "rosetta_translation_keys", force: :cascade do |t|
- t.text "value"
+ create_table "rosetta_text_entries", force: :cascade do |t|
+ t.text "content", null: false
+ t.bigint "locale_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.index ["value"], name: "index_rosetta_translation_keys_on_value", unique: true
+ t.index ["content"], name: "index_rosetta_text_entries_on_content"
+ t.index ["locale_id", "content"], name: "index_rosetta_text_entries_on_locale_id_and_content", unique: true
+ t.index ["locale_id"], name: "index_rosetta_text_entries_on_locale_id"
end
create_table "rosetta_translations", force: :cascade do |t|
- t.text "value"
- t.integer "locale_id", null: false
- t.integer "translation_key_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.index ["locale_id", "translation_key_id"], name: "index_rosetta_translations_on_locale_id_and_translation_key_id", unique: true
- t.index ["locale_id"], name: "index_rosetta_translations_on_locale_id"
- t.index ["translation_key_id"], name: "index_rosetta_translations_on_translation_key_id"
+ t.bigint "target_locale_id", null: false
+ t.bigint "from_id", null: false
+ t.bigint "to_id", null: false
+ t.index ["from_id"], name: "index_rosetta_translations_on_from_id"
+ t.index ["target_locale_id", "from_id", "to_id"], name: "rosetta_translations_uniqueness", unique: true
+ t.index ["target_locale_id"], name: "index_rosetta_translations_on_target_locale_id"
+ t.index ["to_id"], name: "index_rosetta_translations_on_to_id"
end
- add_foreign_key "rosetta_translations", "rosetta_locales", column: "locale_id"
- add_foreign_key "rosetta_translations", "rosetta_translation_keys", column: "translation_key_id"
+ add_foreign_key "rosetta_text_entries", "rosetta_locales", column: "locale_id"
+ add_foreign_key "rosetta_translations", "rosetta_locales", column: "target_locale_id"
+ add_foreign_key "rosetta_translations", "rosetta_text_entries", column: "from_id"
+ add_foreign_key "rosetta_translations", "rosetta_text_entries", column: "to_id"
end
diff --git a/test/fixtures/rosetta/text_entries.yml b/test/fixtures/rosetta/text_entries.yml
new file mode 100644
index 0000000..83c9145
--- /dev/null
+++ b/test/fixtures/rosetta/text_entries.yml
@@ -0,0 +1,17 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+hello:
+ content: hello
+ locale: english
+
+bonjour:
+ content: bonjour
+ locale: french
+
+hola:
+ content: hola
+ locale: spanish
+
+goodbye:
+ content: goodbye
+ locale: english
diff --git a/test/fixtures/rosetta/translation_keys.yml b/test/fixtures/rosetta/translation_keys.yml
deleted file mode 100644
index c9b3753..0000000
--- a/test/fixtures/rosetta/translation_keys.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-hello:
- value: hello
-
-goodbye:
- value: goodbye
diff --git a/test/fixtures/rosetta/translations.yml b/test/fixtures/rosetta/translations.yml
index c0bd65c..8592cdb 100644
--- a/test/fixtures/rosetta/translations.yml
+++ b/test/fixtures/rosetta/translations.yml
@@ -1,9 +1,9 @@
-french_hello:
- translation_key: hello
- locale: french
- value: bonjour
+hello_from_english_to_french:
+ from: hello
+ to: bonjour
+ target_locale: french
-spanish_hello:
- translation_key: hello
- locale: spanish
- value: hola
+hello_from_english_to_spanish:
+ from: hello
+ to: hola
+ target_locale: spanish
diff --git a/test/integration/translations_test.rb b/test/integration/translations_test.rb
index 6e1a920..4242e9e 100644
--- a/test/integration/translations_test.rb
+++ b/test/integration/translations_test.rb
@@ -22,10 +22,10 @@ class TranslationsTest < ActionDispatch::IntegrationTest
test "deploying a new translation" do
locale = rosetta_locales(:french)
- key = Rosetta::TranslationKey.create(value: "Available locales")
+ key = Rosetta::TextEntry.create(content: "Available locales", locale: rosetta_locales(:english))
# Create the translation
- patch rosetta.translation_key_translation_path(key), params: { locale_id: locale.id, translation_key: { value_fr: "Langues disponibles" } }
+ patch rosetta.text_entry_translation_path(key), params: { locale_id: locale.id, text_entry: { content_fr: "Langues disponibles" } }
# Deploy the changes
post rosetta.locale_deploys_path(locale)
diff --git a/test/jobs/rosetta/autodiscovery_job_test.rb b/test/jobs/rosetta/autodiscovery_job_test.rb
index 4ad4956..799c537 100644
--- a/test/jobs/rosetta/autodiscovery_job_test.rb
+++ b/test/jobs/rosetta/autodiscovery_job_test.rb
@@ -3,13 +3,13 @@
module Rosetta
class AutodiscoveryJobTest < ActiveJob::TestCase
test "creates a new key" do
- assert_difference "Rosetta::TranslationKey.count", 1 do
+ assert_difference "Rosetta::TextEntry.count", 1 do
Rosetta::AutodiscoveryJob.perform_now("Test creation from job")
end
end
test "ignores duplicate keys" do
- TranslationKey.create(value: "duplicate")
+ TextEntry.create(content: "duplicate", locale: rosetta_locales(:english))
perform_enqueued_jobs do
assert_nothing_raised do
diff --git a/test/lib/rosetta/translated_test.rb b/test/lib/rosetta/translated_test.rb
index 7d09fda..63c2acf 100644
--- a/test/lib/rosetta/translated_test.rb
+++ b/test/lib/rosetta/translated_test.rb
@@ -4,29 +4,31 @@ class Rosetta::TranslatedTest < ActiveSupport::TestCase
include ActiveJob::TestHelper
test "setting a new translation" do
- translation_key = rosetta_translation_keys(:goodbye)
- translation_key.update(value_fr: "au revoir")
- translation_key.reload
+ text_entry = rosetta_text_entries(:goodbye)
+ text_entry.update(content_fr: "au revoir")
+ text_entry.reload
- assert_equal "au revoir", translation_key.value_fr
- assert_not_nil translation_key.fr_translation
+ assert_equal "au revoir", text_entry.content_fr
+ assert_not_nil text_entry.fr_translation
end
- test "setting a translation to blank removes the translation" do
- translation_key = rosetta_translation_keys(:hello)
+ test "setting a new translation to an existing entry does not create a new entry" do
+ text_entry = Rosetta::TextEntry.create(content: "good morning", locale: rosetta_locales(:english))
- translation_key.update(value_fr: "")
- translation_key.reload
+ assert_no_difference "Rosetta::TextEntry.count" do
+ text_entry.update(content_fr: "bonjour")
+ end
- assert_nil translation_key.value_fr
- assert_nil translation_key.fr_translation
+ assert_equal "bonjour", text_entry.reload.content_fr
end
- test "setting a translation without saving returns the updated translation" do
- translation_key = rosetta_translation_keys(:hello)
- translation_key.value_fr = "salut"
+ test "setting a translation to blank removes the translation" do
+ text_entry = rosetta_text_entries(:hello)
+
+ text_entry.update(content_fr: "")
+ text_entry.reload
- assert_equal "salut", translation_key.value_fr
- assert_equal "bonjour", translation_key.reload.value_fr
+ assert_nil text_entry.content_fr
+ assert_nil text_entry.fr_translation
end
end
diff --git a/test/models/rosetta/text_entry_test.rb b/test/models/rosetta/text_entry_test.rb
new file mode 100644
index 0000000..662c031
--- /dev/null
+++ b/test/models/rosetta/text_entry_test.rb
@@ -0,0 +1,9 @@
+require "test_helper"
+
+class Rosetta::TextEntryTest < ActiveSupport::TestCase
+ test "purge does nothing when a translation exists" do
+ assert_no_difference -> { Rosetta::TextEntry.count } do
+ rosetta_text_entries(:bonjour).purge
+ end
+ end
+end
diff --git a/test/models/rosetta/translation_test.rb b/test/models/rosetta/translation_test.rb
index 9ecaa94..f65fe52 100644
--- a/test/models/rosetta/translation_test.rb
+++ b/test/models/rosetta/translation_test.rb
@@ -4,10 +4,9 @@ module Rosetta
class TranslationTest < ActiveSupport::TestCase
test "Adding the same translation twice raises" do
locale = rosetta_locales(:french)
- key = rosetta_translation_keys(:hello)
assert_raises ActiveRecord::RecordNotUnique do
- Rosetta::Translation.create(locale: locale, translation_key: key, value: "bonjour x2")
+ Rosetta::Translation.create(target_locale: locale, from: rosetta_text_entries(:hello), to: rosetta_text_entries(:bonjour))
end
end
end
diff --git a/test/rosetta_test.rb b/test/rosetta_test.rb
index 2a54cac..566f480 100644
--- a/test/rosetta_test.rb
+++ b/test/rosetta_test.rb
@@ -25,7 +25,7 @@ class RosettaTest < ActiveSupport::TestCase
assert_equal Rosetta.locale, Rosetta::Locale.default_locale
end
- test "#translate translates the key in the selected loacle" do
+ test "#translate translates the key in the selected locale" do
Rosetta.with_locale(rosetta_locales(:french)) { assert_equal "bonjour", Rosetta.translate("hello") }
assert_equal "bonjour", Rosetta.translate("hello", locale: rosetta_locales(:french))
assert_equal "hola", Rosetta.translate("hello", locale: rosetta_locales(:spanish))
diff --git a/test/test_helper.rb b/test/test_helper.rb
index d911616..ea4538d 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -22,15 +22,30 @@
# End Note
class ActiveSupport::TestCase
+ setup do
+ reset_locale_setup
+ ensure_translation_associations_loaded
+ end
+
+ private
+
# Provide a clean slate for each test:
# - Unset the default locale
- # - Reset the registered classes for translations
# - Reload all locale stores
+ # - Reset the registered classes for translations
# - Set the locale to the default locale
- setup do
+ def reset_locale_setup
Rosetta::Locale.default_locale = nil
- Rosetta::Locale.registered_classes_for_translations = []
Rosetta::Store.locale_stores.each { |code, store| store.reload! }
+ Rosetta::Locale.registered_classes_for_translations = []
Rosetta.locale = :en
end
+
+ # Fixtures are loaded after the code, hence association for the locale fixtures
+ # are not loaded when the tests start.
+ def ensure_translation_associations_loaded
+ return if Rosetta::TextEntry.respond_to?(:fr_translation)
+
+ Rosetta::TextEntry.translate_in_all_locales
+ end
end