このコミットが含まれているのは:
@@ -24,17 +24,7 @@ FactoryBot.define do
|
||||
|
||||
evaluator.primary_tag_name.update!(tag:, primary_flg: true)
|
||||
|
||||
Locale.where(deprecated_at: nil).order(:language_code, :created_at, :script_code).to_a
|
||||
.uniq(&:language_code).each do |locale|
|
||||
next if tag.tag_names.exists?(language_code: locale.language_code,
|
||||
primary_flg: true)
|
||||
|
||||
create(:tag_name,
|
||||
tag:, language_code: locale.language_code,
|
||||
script_code: locale.script_code,
|
||||
name: TagName.generate_name(locale, tag, evaluator.primary_tag_name),
|
||||
primary_flg: true, auto_generated: true)
|
||||
end
|
||||
TagNameCompletion.for_tag!(tag)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,9 +6,8 @@ RSpec.describe Language, type: :model do
|
||||
expect(described_class.where(deprecated_at: nil).pluck(:code)).to eq(['ja'])
|
||||
end
|
||||
|
||||
it 'accepts English when multilingual support is enabled' do
|
||||
pending '日本語以外の Language 有効化は別課題で実装する'
|
||||
expect { described_class.create!(code: 'en', name: 'English') }
|
||||
it 'accepts Ainu when multilingual support is enabled' do
|
||||
expect { described_class.create!(code: 'ain', name: 'ain') }
|
||||
.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Locale activation', type: :model do
|
||||
let!(:language) { Language.create!(code: 'ain', name: 'ain') }
|
||||
let!(:script) { Script.create!(code: 'Kana', name: 'Kana') }
|
||||
let!(:first) { create(:tag, primary_name: 'activation_first') }
|
||||
let!(:second) { create(:tag, primary_name: 'activation_second') }
|
||||
|
||||
def build_locale deprecated_at: nil
|
||||
Locale.new(code: 'ain-Kana', language_code: language.code,
|
||||
script_code: script.code, region_code: 392, variants: '',
|
||||
name: 'ain-Kana', deprecated_at:)
|
||||
end
|
||||
|
||||
def generated_names
|
||||
TagName.where(language_code: 'ain', primary_flg: true)
|
||||
end
|
||||
|
||||
def fail_second_generation!
|
||||
allow(TagName).to receive(:generate_name).and_call_original
|
||||
allow(TagName).to receive(:generate_name)
|
||||
.with(kind_of(Locale), second, second.tag_name('ja'))
|
||||
.and_raise('backfill failed')
|
||||
end
|
||||
|
||||
it 'rolls back a newly created locale and the preceding generated names' do
|
||||
locale = build_locale
|
||||
fail_second_generation!
|
||||
|
||||
expect { locale.save! }.to raise_error('backfill failed')
|
||||
|
||||
expect(Locale.exists?(code: 'ain-Kana')).to be(false)
|
||||
expect(generated_names).to be_empty
|
||||
expect(first.reload.name('ja')).to eq('activation_first')
|
||||
expect(second.reload.name('ja')).to eq('activation_second')
|
||||
end
|
||||
|
||||
it 'does not backfill while the locale is inactive' do
|
||||
build_locale(deprecated_at: Time.current).save!
|
||||
|
||||
expect(generated_names).to be_empty
|
||||
end
|
||||
|
||||
it 'backfills missing primary names when the locale becomes active' do
|
||||
locale = build_locale(deprecated_at: Time.current)
|
||||
locale.save!
|
||||
|
||||
locale.update!(deprecated_at: nil)
|
||||
|
||||
expect(generated_names.pluck(:tag_id)).to contain_exactly(first.id, second.id)
|
||||
expect(generated_names).to all(have_attributes(
|
||||
script_code: 'Kana', primary_flg: true, auto_generated: true))
|
||||
end
|
||||
|
||||
it 'rolls back activation and all generated names when backfill fails' do
|
||||
locale = build_locale(deprecated_at: Time.current)
|
||||
locale.save!
|
||||
previous_deprecated_at = locale.reload.deprecated_at
|
||||
fail_second_generation!
|
||||
|
||||
expect { locale.update!(deprecated_at: nil) }.to raise_error('backfill failed')
|
||||
|
||||
expect(locale.reload.deprecated_at).to eq(previous_deprecated_at)
|
||||
expect(generated_names).to be_empty
|
||||
end
|
||||
|
||||
it 'preserves a human primary through deactivation and repeated activation' do
|
||||
locale = build_locale
|
||||
locale.save!
|
||||
primary = generated_names.find_by!(tag: first)
|
||||
primary.update!(name: 'human_confirmed', auto_generated: false)
|
||||
snapshot = generated_names.order(:id).map(&:attributes)
|
||||
|
||||
2.times do
|
||||
locale.update!(deprecated_at: Time.current)
|
||||
locale.update!(deprecated_at: nil)
|
||||
end
|
||||
|
||||
expect(generated_names.order(:id).map(&:attributes)).to eq(snapshot)
|
||||
expect(primary.reload).to have_attributes(name: 'human_confirmed', auto_generated: false)
|
||||
end
|
||||
end
|
||||
@@ -1,13 +1,13 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Locale, type: :model do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
def create_english_locale!
|
||||
prepare_english_reference!
|
||||
described_class.create!(code: 'en', language_code: 'en',
|
||||
script_code: 'Latn', region_code: 826,
|
||||
variants: '', name: 'English')
|
||||
def create_ainu_locale!
|
||||
prepare_ainu_reference!
|
||||
described_class.create!(code: 'ain-Kana', language_code: 'ain',
|
||||
script_code: 'Kana', region_code: 392,
|
||||
variants: '', name: 'Ainu')
|
||||
end
|
||||
|
||||
it 'keeps the active Nipponese locale consistent with its identity tuple' do
|
||||
@@ -27,7 +27,6 @@ RSpec.describe Locale, type: :model do
|
||||
end
|
||||
|
||||
it 'generates a primary name for every existing tag using the name generator' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
first = create(:tag, primary_name: 'first_existing_tag')
|
||||
second = create(:tag, primary_name: 'second_existing_tag')
|
||||
allow(TagName).to receive(:generate_name).and_call_original
|
||||
@@ -35,63 +34,60 @@ RSpec.describe Locale, type: :model do
|
||||
.with(kind_of(described_class), first, primary_tag_name_for(first, 'ja'))
|
||||
.and_return('name_from_generator')
|
||||
|
||||
locale = create_english_locale!
|
||||
locale = create_ainu_locale!
|
||||
|
||||
expect(TagName).to have_received(:generate_name)
|
||||
.with(locale, first, primary_tag_name_for(first, 'ja'))
|
||||
expect(TagName).to have_received(:generate_name)
|
||||
.with(locale, second, primary_tag_name_for(second, 'ja'))
|
||||
expect(first.tag_names.find_by!(language_code: 'en', primary_flg: true))
|
||||
expect(first.tag_names.find_by!(language_code: 'ain', primary_flg: true))
|
||||
.to have_attributes(name: 'name_from_generator', tag_id: first.id,
|
||||
language_code: 'en', script_code: 'Latn',
|
||||
language_code: 'ain', script_code: 'Kana',
|
||||
primary_flg: true, auto_generated: true)
|
||||
expect(second.tag_names.find_by!(language_code: 'en', primary_flg: true))
|
||||
.to have_attributes(tag_id: second.id, language_code: 'en',
|
||||
script_code: 'Latn', primary_flg: true,
|
||||
expect(second.tag_names.find_by!(language_code: 'ain', primary_flg: true))
|
||||
.to have_attributes(tag_id: second.id, language_code: 'ain',
|
||||
script_code: 'Kana', primary_flg: true,
|
||||
auto_generated: true)
|
||||
expect(TagName.where(language_code: 'en', primary_flg: true,
|
||||
expect(TagName.where(language_code: 'ain', primary_flg: true,
|
||||
tag_id: [first.id, second.id]).count).to eq(2)
|
||||
end
|
||||
|
||||
it 'does not duplicate an existing primary name in the new language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_reference!
|
||||
prepare_ainu_reference!
|
||||
tag = create(:tag, primary_name: 'already_named')
|
||||
existing = create(:tag_name, name: 'existing_english', tag:,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
existing = create(:tag_name, name: 'existing_ainu', tag:,
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
create_english_locale!
|
||||
create_ainu_locale!
|
||||
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'en', primary_flg: true))
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'ain', primary_flg: true))
|
||||
.to contain_exactly(existing)
|
||||
expect(existing.reload).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'en', script_code: 'Latn',
|
||||
tag_id: tag.id, language_code: 'ain', script_code: 'Kana',
|
||||
primary_flg: true, auto_generated: false)
|
||||
end
|
||||
|
||||
it 'creates a primary name when the language has only an alias' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_reference!
|
||||
prepare_ainu_reference!
|
||||
tag = create(:tag, primary_name: 'alias_only_tag')
|
||||
alias_name = create(:tag_name, :alias, name: 'alias_en',
|
||||
tag:,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
create_english_locale!
|
||||
create_ainu_locale!
|
||||
|
||||
expect(alias_name.reload).to have_attributes(
|
||||
tag_id: tag.id,
|
||||
language_code: 'en', script_code: 'Latn', primary_flg: false)
|
||||
generated = TagName.find_by!(tag_id: tag.id, language_code: 'en', primary_flg: true)
|
||||
expect(generated).to have_attributes(tag_id: tag.id, language_code: 'en',
|
||||
script_code: 'Latn', primary_flg: true,
|
||||
language_code: 'ain', script_code: 'Kana', primary_flg: false)
|
||||
generated = TagName.find_by!(tag_id: tag.id, language_code: 'ain', primary_flg: true)
|
||||
expect(generated).to have_attributes(tag_id: tag.id, language_code: 'ain',
|
||||
script_code: 'Kana', primary_flg: true,
|
||||
auto_generated: true)
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'en', primary_flg: true).count).to eq(1)
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'ain', primary_flg: true).count).to eq(1)
|
||||
end
|
||||
|
||||
it 'rolls back the locale and all generated names when backfill fails' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_reference!
|
||||
prepare_ainu_reference!
|
||||
first = create(:tag, primary_name: 'atomic_first')
|
||||
second = create(:tag, primary_name: 'atomic_second')
|
||||
allow(TagName).to receive(:generate_name).and_call_original
|
||||
@@ -99,31 +95,27 @@ RSpec.describe Locale, type: :model do
|
||||
.with(kind_of(described_class), second, primary_tag_name_for(second, 'ja'))
|
||||
.and_raise('backfill failed')
|
||||
|
||||
expect { create_english_locale! }.to raise_error('backfill failed')
|
||||
expect { create_ainu_locale! }.to raise_error('backfill failed')
|
||||
|
||||
expect(described_class.exists?(code: 'en')).to be(false)
|
||||
expect(TagName.where(language_code: 'en', tag_id: [first.id, second.id])).to be_empty
|
||||
expect(described_class.exists?(code: 'ain-Kana')).to be(false)
|
||||
expect(TagName.where(language_code: 'ain', tag_id: [first.id, second.id])).to be_empty
|
||||
end
|
||||
|
||||
it 'accepts a stable locale code outside the historical enum values' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_reference!
|
||||
it 'rejects a private locale code outside the supported locale set' do
|
||||
prepare_ainu_reference!
|
||||
|
||||
locale = described_class.create!(
|
||||
code: 'en-x-rspec', language_code: 'en',
|
||||
script_code: 'Latn', region_code: 826,
|
||||
variants: 'x-rspec', name: 'English')
|
||||
|
||||
expect(locale.reload).to have_attributes(
|
||||
code: 'en-x-rspec', language_code: 'en', script_code: 'Latn',
|
||||
region_code: 826, variants: 'x-rspec')
|
||||
expect {
|
||||
described_class.create!(
|
||||
code: 'ain-Kana-x-rspec', language_code: 'ain',
|
||||
script_code: 'Kana', region_code: 392,
|
||||
variants: 'x-rspec', name: 'Ainu')
|
||||
}.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'registers the future British English locale tuple' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'registers the supported Ainu locale tuple' do
|
||||
|
||||
expect(locale).to have_attributes(code: 'en', language_code: 'en',
|
||||
script_code: 'Latn', region_code: 826,
|
||||
expect(locale).to have_attributes(code: 'ain-Kana', language_code: 'ain',
|
||||
script_code: 'Kana', region_code: 392,
|
||||
variants: '')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Script, type: :model do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'selects locales by script code, not language code' do
|
||||
expect(described_class.find('Jpan').locales).to contain_exactly(Locale.nipponese)
|
||||
@@ -25,11 +25,10 @@ RSpec.describe Script, type: :model do
|
||||
}
|
||||
end
|
||||
|
||||
it 'selects Latin locales when multilingual support is enabled' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'selects Kana locales when multilingual support is enabled' do
|
||||
locale
|
||||
|
||||
expect(described_class.find('Latn').locales).to contain_exactly(locale)
|
||||
expect(described_class.find('Kana').locales).to contain_exactly(locale)
|
||||
expect(described_class.find('Jpan').locales).not_to include(locale)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,38 +95,36 @@ RSpec.describe TagNameSanitisationRule, type: :model do
|
||||
end
|
||||
|
||||
context 'when only another language has the sanitised name' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'keeps both names when sanitisation produces a cross-language match' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag_name, name: 'foobar')
|
||||
english = create(:tag_name, name: 'temporary',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english.update_columns(name: 'foo_bar')
|
||||
ainu = create(:tag_name, name: 'temporary',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu.update_columns(name: 'foo_bar')
|
||||
|
||||
expect { described_class.apply! }.not_to change(TagName, :count)
|
||||
|
||||
expect(english.reload).to have_attributes(name: 'foobar', language_code: 'en')
|
||||
expect(ainu.reload).to have_attributes(name: 'foobar', language_code: 'ain')
|
||||
expect(nipponese.reload).to have_attributes(name: 'foobar', language_code: 'ja')
|
||||
end
|
||||
|
||||
it 'renames without merging tags or deleting either language identity' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag, primary_name: 'foobar')
|
||||
english_name = create(:tag_name, name: 'temporary',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, primary_tag_name: english_name)
|
||||
english_name.update_columns(name: 'foo_bar')
|
||||
ainu_name = create(:tag_name, name: 'temporary',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu = create(:tag, primary_tag_name: ainu_name)
|
||||
ainu_name.update_columns(name: 'foo_bar')
|
||||
|
||||
described_class.apply!
|
||||
|
||||
expect(english_name.reload).to have_attributes(
|
||||
name: 'foobar', language_code: 'en', tag_id: english.id)
|
||||
expect(ainu_name.reload).to have_attributes(
|
||||
name: 'foobar', language_code: 'ain', tag_id: ainu.id)
|
||||
expect(primary_tag_name_for(nipponese.reload, 'ja')).to have_attributes(
|
||||
name: 'foobar', language_code: 'ja', tag_id: nipponese.id)
|
||||
expect(primary_tag_name_for(english.reload, 'en')).to eq(english_name)
|
||||
expect(primary_tag_name_for(ainu.reload, 'ain')).to eq(ainu_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagName, type: :model do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'allows the same name in different languages' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
create(:tag_name, name: 'shared_name')
|
||||
english = build(:tag_name, name: 'shared_name',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
ainu = build(:tag_name, name: 'shared_name',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
expect(english).to be_valid
|
||||
expect { english.save! }.to change(described_class, :count).by(1)
|
||||
expect(ainu).to be_valid
|
||||
expect { ainu.save! }.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
it 'rejects a duplicate name within the same language' do
|
||||
@@ -67,11 +66,10 @@ RSpec.describe TagName, type: :model do
|
||||
end
|
||||
|
||||
it 'completes an ordinary tag factory under future active languages' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tag = create(:tag, primary_name: 'future_factory')
|
||||
|
||||
expect(TagName.where(tag:, language_code: 'en', primary_flg: true))
|
||||
expect(TagName.where(tag:, language_code: 'ain', primary_flg: true))
|
||||
.to contain_exactly(have_attributes(auto_generated: true))
|
||||
end
|
||||
|
||||
@@ -114,46 +112,44 @@ RSpec.describe TagName, type: :model do
|
||||
end
|
||||
|
||||
it 'resolves the primary name of the alias language on the same tag' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tag = create(:tag, primary_name: '日本語正本')
|
||||
english_primary = primary_tag_name_for(tag, 'en')
|
||||
english_primary.update!(name: 'english_primary', auto_generated: false)
|
||||
english_alias = create(:tag_name, :alias, tag:, name: 'english_alias',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
ainu_primary = primary_tag_name_for(tag, 'ain')
|
||||
ainu_primary.update!(name: 'ainu_primary', auto_generated: false)
|
||||
ainu_alias = create(:tag_name, :alias, tag:, name: 'ainu_alias',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
representative_id = tag.tag_name('ja')&.id
|
||||
|
||||
primary = described_class.find_by!(tag_id: english_alias.tag_id,
|
||||
language_code: english_alias.language_code,
|
||||
primary = described_class.find_by!(tag_id: ainu_alias.tag_id,
|
||||
language_code: ainu_alias.language_code,
|
||||
primary_flg: true)
|
||||
|
||||
expect(primary).to eq(english_primary)
|
||||
expect(described_class.canonicalise(locale, [english_alias.name]))
|
||||
.to eq([english_primary.name])
|
||||
expect(primary).to eq(ainu_primary)
|
||||
expect(described_class.canonicalise(locale, [ainu_alias.name]))
|
||||
.to eq([ainu_primary.name])
|
||||
expect(tag.reload.tag_name('ja')&.id).to eq(representative_id)
|
||||
end
|
||||
|
||||
it 'resolves only aliases in the requested language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag, primary_name: 'nipponese_canonical')
|
||||
english_name = create(:tag_name, name: 'english_canonical',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, primary_tag_name: english_name)
|
||||
ainu_name = create(:tag_name, name: 'ainu_canonical',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu = create(:tag, primary_tag_name: ainu_name)
|
||||
nipponese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: nipponese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
ainu_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: ainu,
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
expect(nipponese_alias.reload).to have_attributes(
|
||||
tag_id: nipponese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(ainu_alias.reload).to have_attributes(
|
||||
tag_id: ainu.id,
|
||||
primary_flg: false, language_code: 'ain')
|
||||
expect(described_class.canonicalise(locale, ['shared_alias']))
|
||||
.to eq(['english_canonical'])
|
||||
.to eq(['ainu_canonical'])
|
||||
expect(described_class.canonicalise(Locale.nipponese, ['shared_alias']))
|
||||
.to eq(['nipponese_canonical'])
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ RSpec.describe Tag, type: :model do
|
||||
it 'checks the requested language and treats an empty description as present' do
|
||||
TagDescription.create!(tag:, language_code: 'ja', body: '', version_no: 1)
|
||||
expect(tag.has_description?(language_code: 'ja')).to be(true)
|
||||
expect(tag.has_description?(language_code: 'en')).to be(false)
|
||||
expect(tag.has_description?(language_code: 'ain')).to be(false)
|
||||
end
|
||||
|
||||
it 'returns false without a description' do
|
||||
@@ -23,16 +23,16 @@ RSpec.describe Tag, type: :model do
|
||||
subscriber = ->(*args) { queries << args.last.fetch(:sql) }
|
||||
ActiveSupport::Notifications.subscribed(subscriber, 'sql.active_record') do
|
||||
expect(loaded.has_description?(language_code: 'ja')).to be(true)
|
||||
expect(loaded.has_description?(language_code: 'en')).to be(false)
|
||||
expect(loaded.has_description?(language_code: 'ain')).to be(false)
|
||||
end
|
||||
expect(queries).to be_empty
|
||||
end
|
||||
|
||||
it 'keeps language selection generic without enabling another Language record' do
|
||||
tag.association(:tag_descriptions).target = [
|
||||
TagDescription.new(tag:, language_code: 'en', body: '', version_no: 1)]
|
||||
TagDescription.new(tag:, language_code: 'ain', body: '', version_no: 1)]
|
||||
tag.association(:tag_descriptions).loaded!
|
||||
expect(tag.has_description?(language_code: 'en')).to be(true)
|
||||
expect(tag.has_description?(language_code: 'ain')).to be(true)
|
||||
expect(tag.has_description?(language_code: 'ja')).to be(false)
|
||||
end
|
||||
end
|
||||
@@ -61,33 +61,32 @@ RSpec.describe Tag, type: :model do
|
||||
end
|
||||
|
||||
describe '.normalise_tags!' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'canonicalises aliases in the supplied language only' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_reference!
|
||||
prepare_ainu_reference!
|
||||
nipponese = create(:tag, primary_name: 'nipponese_canonical')
|
||||
english_name = create(:tag_name, name: 'english_canonical',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, primary_tag_name: english_name)
|
||||
primary_tag_name_for(english, 'ja').update!(
|
||||
name: 'english_in_nipponese', auto_generated: false)
|
||||
english_locale = locale
|
||||
ainu_name = create(:tag_name, name: 'ainu_canonical',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu = create(:tag, primary_tag_name: ainu_name)
|
||||
primary_tag_name_for(ainu, 'ja').update!(
|
||||
name: 'ainu_in_nipponese', auto_generated: false)
|
||||
ainu_locale = locale
|
||||
nipponese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: nipponese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
ainu_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: ainu,
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
expect(nipponese_alias.reload).to have_attributes(
|
||||
tag_id: nipponese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(ainu_alias.reload).to have_attributes(
|
||||
tag_id: ainu.id,
|
||||
primary_flg: false, language_code: 'ain')
|
||||
expect(described_class.normalise_tags!(
|
||||
english_locale, ['shared_alias'],
|
||||
with_tagme: false, with_no_deerjikist: false)).to eq([english])
|
||||
ainu_locale, ['shared_alias'],
|
||||
with_tagme: false, with_no_deerjikist: false)).to eq([ainu])
|
||||
expect(described_class.normalise_tags!(
|
||||
Locale.nipponese, ['shared_alias'],
|
||||
with_tagme: false, with_no_deerjikist: false)).to eq([nipponese])
|
||||
@@ -253,129 +252,120 @@ RSpec.describe Tag, type: :model do
|
||||
|
||||
describe '.find_or_create_by_tag_name!' do
|
||||
context 'with an explicit locale' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'creates the representative name with locale attributes and ownership' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tag = described_class.find_or_create_by_tag_name!(
|
||||
locale, 'english_name', category: :character)
|
||||
locale, 'ainu_name', category: :character)
|
||||
|
||||
expect(primary_tag_name_for(tag, 'en')).to have_attributes(
|
||||
language_code: 'en', script_code: 'Latn',
|
||||
expect(primary_tag_name_for(tag, 'ain')).to have_attributes(
|
||||
language_code: 'ain', script_code: 'Kana',
|
||||
primary_flg: true, tag_id: tag.id)
|
||||
expect(tag.category).to eq('character')
|
||||
end
|
||||
|
||||
it 'uses the English primary as the source for a generated Nipponese name' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'uses a Japanese fallback for an Ainu-origin tag without reverse transcription' do
|
||||
locale
|
||||
allow(TagName).to receive(:generate_name).and_return('generated_nipponese')
|
||||
allow(TagName).to receive(:generate_name).and_call_original
|
||||
|
||||
tag = described_class.find_or_create_by_tag_name!(
|
||||
locale, 'english_origin', category: :general)
|
||||
locale, 'ainu_origin', category: :general)
|
||||
|
||||
expect(TagName.where(tag:, language_code: 'en', primary_flg: true))
|
||||
expect(TagName.where(tag:, language_code: 'ain', primary_flg: true))
|
||||
.to contain_exactly(have_attributes(
|
||||
name: 'english_origin', auto_generated: false))
|
||||
name: 'ainu_origin', auto_generated: false))
|
||||
expect(TagName.where(tag:, language_code: 'ja', primary_flg: true))
|
||||
.to contain_exactly(have_attributes(
|
||||
name: 'generated_nipponese', auto_generated: true))
|
||||
source_tag_name = TagName.find_by!(tag:, language_code: 'en', primary_flg: true)
|
||||
name: "Tag_##{ tag.id }", auto_generated: true))
|
||||
expect(TagName).to have_received(:generate_name)
|
||||
.with(Locale.nipponese, tag, source_tag_name)
|
||||
.with(Locale.nipponese, tag, nil)
|
||||
end
|
||||
|
||||
it 'gives a new tag one primary name for every active language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tag = described_class.find_or_create_by_tag_name!(
|
||||
Locale.nipponese, 'new_multilingual_tag', category: :general)
|
||||
|
||||
expect(TagName.where(tag:, language_code: 'ja', primary_flg: true).count).to eq(1)
|
||||
expect(TagName.where(tag:, language_code: 'en', primary_flg: true).count).to eq(1)
|
||||
expect(TagName.where(tag:, language_code: 'ain', primary_flg: true).count).to eq(1)
|
||||
end
|
||||
|
||||
it 'creates one primary per language when multiple locales use English' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'creates one primary per language when multiple locales use Ainu' do
|
||||
locale
|
||||
described_class.find_or_create_by_tag_name!(
|
||||
locale, 'before_second_english_locale', category: :general)
|
||||
Locale.create!(code: 'en-x-rspec', language_code: 'en',
|
||||
script_code: 'Latn', region_code: 826,
|
||||
variants: 'x-rspec', name: 'English')
|
||||
locale, 'before_second_ainu_locale', category: :general)
|
||||
|
||||
tag = described_class.find_or_create_by_tag_name!(
|
||||
locale, 'one_english_primary', category: :general)
|
||||
locale, 'one_ainu_primary', category: :general)
|
||||
TagNameCompletion.for_tag!(tag, locales: [locale, locale.dup, Locale.nipponese])
|
||||
|
||||
expect(TagName.where(tag:, language_code: 'en', primary_flg: true).count).to eq(1)
|
||||
expect(TagName.where(tag:, language_code: 'ain', primary_flg: true).count).to eq(1)
|
||||
expect(TagName.where(tag:, language_code: 'ja', primary_flg: true).count).to eq(1)
|
||||
end
|
||||
|
||||
it 'rolls back a new tag and requested name if name generation fails' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
original_tag_count = described_class.count
|
||||
allow(TagName).to receive(:generate_name).and_raise('generation failed')
|
||||
|
||||
expect {
|
||||
described_class.find_or_create_by_tag_name!(
|
||||
locale, 'atomic_english_name', category: :general)
|
||||
locale, 'atomic_ainu_name', category: :general)
|
||||
}.to raise_error('generation failed')
|
||||
|
||||
expect(described_class.count).to eq(original_tag_count)
|
||||
expect(TagName.where(language_code: 'en', name: 'atomic_english_name')).to be_empty
|
||||
expect(TagName.where(language_code: 'ain', name: 'atomic_ainu_name')).to be_empty
|
||||
expect(described_class.joins(:tag_names)
|
||||
.where(tag_names: { name: 'atomic_english_name' })).to be_empty
|
||||
.where(tag_names: { name: 'atomic_ainu_name' })).to be_empty
|
||||
end
|
||||
|
||||
|
||||
|
||||
it 'creates separate tag identities for the same name in different languages' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = described_class.find_or_create_by_tag_name!(
|
||||
Locale.nipponese, 'same_name', category: :general)
|
||||
english = described_class.find_or_create_by_tag_name!(
|
||||
primary_tag_name_for(nipponese, 'ain').update!(
|
||||
name: 'other_ainu_name', auto_generated: false)
|
||||
ainu = described_class.find_or_create_by_tag_name!(
|
||||
locale, 'same_name', category: :character)
|
||||
|
||||
expect(english).not_to eq(nipponese)
|
||||
expect(primary_tag_name_for(english, 'en')).to have_attributes(
|
||||
name: 'same_name', tag_id: english.id, language_code: 'en', primary_flg: true)
|
||||
expect(ainu).not_to eq(nipponese)
|
||||
expect(primary_tag_name_for(ainu, 'ain')).to have_attributes(
|
||||
name: 'same_name', tag_id: ainu.id, language_code: 'ain', primary_flg: true)
|
||||
expect(primary_tag_name_for(nipponese, 'ja')).to have_attributes(
|
||||
name: 'same_name', tag_id: nipponese.id, language_code: 'ja', primary_flg: true)
|
||||
expect(described_class.find_or_create_by_tag_name!(
|
||||
locale, 'same_name', category: :general)).to eq(english)
|
||||
locale, 'same_name', category: :general)).to eq(ainu)
|
||||
expect(described_class.find_or_create_by_tag_name!(
|
||||
Locale.nipponese, 'same_name', category: :general)).to eq(nipponese)
|
||||
end
|
||||
|
||||
it 'preserves the V1 representative when looking up another primary language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tag = create(:tag, primary_name: '日本語代表名')
|
||||
representative_id = tag.tag_name('ja')&.id
|
||||
english = primary_tag_name_for(tag, 'en')
|
||||
english.update!(name: 'english_primary', auto_generated: false)
|
||||
ainu = primary_tag_name_for(tag, 'ain')
|
||||
ainu.update!(name: 'ainu_primary', auto_generated: false)
|
||||
|
||||
found = described_class.find_or_create_by_tag_name!(
|
||||
locale, english.name, category: :general)
|
||||
locale, ainu.name, category: :general)
|
||||
|
||||
expect(found).to eq(tag)
|
||||
expect(tag.reload.tag_name('ja')&.id).to eq(representative_id)
|
||||
expect(english.reload.tag_id).to eq(tag.id)
|
||||
expect(ainu.reload.tag_id).to eq(tag.id)
|
||||
end
|
||||
|
||||
it 'normalises names using the supplied locale' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
tags = described_class.normalise_tags!(
|
||||
locale, ['character:normalised_english'],
|
||||
locale, ['character:normalised_ainu'],
|
||||
with_tagme: false, with_no_deerjikist: false)
|
||||
|
||||
expect(tags.length).to eq(1)
|
||||
expect(primary_tag_name_for(tags.first, 'en')).to have_attributes(
|
||||
name: 'normalised_english', language_code: 'en', script_code: 'Latn',
|
||||
expect(primary_tag_name_for(tags.first, 'ain')).to have_attributes(
|
||||
name: 'normalised_ainu', language_code: 'ain', script_code: 'Kana',
|
||||
primary_flg: true, tag_id: tags.first.id)
|
||||
end
|
||||
end
|
||||
@@ -444,26 +434,25 @@ RSpec.describe Tag, type: :model do
|
||||
end
|
||||
|
||||
context 'with names in multiple languages' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'keeps the target primary and moves source names as aliases' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
english_primary = primary_tag_name_for(target_tag, 'en')
|
||||
source_primary = primary_tag_name_for(source_tag, 'en')
|
||||
ainu_primary = primary_tag_name_for(target_tag, 'ain')
|
||||
source_primary = primary_tag_name_for(source_tag, 'ain')
|
||||
source_alias = create(:tag_name, :alias, tag: source_tag,
|
||||
name: 'source_english_alias', language_code: 'en', script_code: 'Latn')
|
||||
name: 'source_ainu_alias', language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
expect([english_primary, source_primary]).to all(have_attributes(
|
||||
expect([ainu_primary, source_primary]).to all(have_attributes(
|
||||
primary_flg: true, auto_generated: true))
|
||||
|
||||
described_class.merge_tags!(target_tag, [source_tag])
|
||||
|
||||
expect(primary_tag_name_for(target_tag.reload, 'en')).to eq(english_primary)
|
||||
expect(TagName.where(tag: target_tag, language_code: 'en', primary_flg: true))
|
||||
.to contain_exactly(english_primary)
|
||||
expect(primary_tag_name_for(target_tag.reload, 'ain')).to eq(ainu_primary)
|
||||
expect(TagName.where(tag: target_tag, language_code: 'ain', primary_flg: true))
|
||||
.to contain_exactly(ainu_primary)
|
||||
expect([source_primary.reload, source_alias.reload]).to all(have_attributes(
|
||||
tag_id: target_tag.id, language_code: 'en', primary_flg: false))
|
||||
tag_id: target_tag.id, language_code: 'ain', primary_flg: false))
|
||||
expect(TagName.where(tag: target_tag, language_code: 'ja', primary_flg: true))
|
||||
.to contain_exactly(primary_tag_name_for(target_tag, 'ja'))
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API locale resolution', type: :request do
|
||||
let!(:tag) { create(:tag, primary_name: '日本語正本') }
|
||||
|
||||
it 'defaults an omitted locale to Japanese' do
|
||||
get "/tags/#{ tag.id }"
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('name')).to eq('日本語正本')
|
||||
end
|
||||
|
||||
it 'accepts an explicitly requested active Japanese locale' do
|
||||
get "/tags/#{ tag.id }", params: { locale: 'ja' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('name')).to eq('日本語正本')
|
||||
end
|
||||
|
||||
['', 'en', 'ain', 'Jpan', 'JA', 'unknown', ['ja']].each do |code|
|
||||
it "rejects invalid locale #{ code.inspect } instead of defaulting to Japanese" do
|
||||
get "/tags/#{ tag.id }", params: { locale: code }
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
expect(response.body).not_to include('日本語正本')
|
||||
end
|
||||
end
|
||||
|
||||
it 'rejects a supported locale that has not been registered' do
|
||||
get "/tags/#{ tag.id }", params: { locale: 'ain-Kana' }
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
|
||||
it 'rejects an inactive locale' do
|
||||
Locale.nipponese.update!(deprecated_at: Time.current)
|
||||
|
||||
get "/tags/#{ tag.id }", params: { locale: 'ja' }
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
|
||||
it 'does not write posts or tag names under an invalid locale' do
|
||||
sign_in_as(create_member_user!)
|
||||
|
||||
expect do
|
||||
post '/posts', params: {
|
||||
locale: 'en', title: 'invalid locale', url: 'https://example.com/invalid-locale',
|
||||
tags: 'unwritten_tag' }
|
||||
end.to change(Post, :count).by(0).and change(TagName, :count).by(0)
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
let(:member) { create(:user, :member) }
|
||||
|
||||
@@ -54,13 +54,12 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
['en', nil].each do |requested_locale|
|
||||
['ain-Kana', nil].each do |requested_locale|
|
||||
context "with locale #{ requested_locale.inspect }" do
|
||||
let(:locale_params) { requested_locale ? { locale: requested_locale } : { } }
|
||||
let(:expected_locale) { requested_locale ? locale : Locale.nipponese }
|
||||
|
||||
it 'creates post tags in the requested language or Nipponese fallback' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
post '/posts', params: locale_params.merge(
|
||||
title: 'Locale post', url: 'https://example.com/locale-post',
|
||||
@@ -72,7 +71,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'updates post tags in the requested language or Nipponese fallback' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
record = create(:post)
|
||||
PostVersionRecorder.record!(post: record, event_type: :create, created_by_user: member)
|
||||
@@ -87,7 +85,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'passes the resolved locale to bulk creation' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
# Worker propagation is exercised in post_bulk_creator_spec.
|
||||
expect_any_instance_of(PostBulkCreator).to receive(:run)
|
||||
@@ -102,7 +99,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'creates materials with tags in the resolved locale' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
post '/materials', params: locale_params.merge(
|
||||
tag: 'locale_material', url: 'https://example.com/material')
|
||||
@@ -113,7 +109,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'updates materials with tags in the resolved locale' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
tag = create(:tag, category: :material)
|
||||
material = Material.create!(tag:, url: 'https://example.com/material')
|
||||
@@ -127,7 +122,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'links Nico external tags to internal tags in the resolved locale' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
external = create(:external_tag)
|
||||
NicoTagVersionRecorder.record!(
|
||||
@@ -141,7 +135,6 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
it 'creates parent tags in the resolved locale' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する' if requested_locale
|
||||
locale if requested_locale
|
||||
tag = create(:tag)
|
||||
|
||||
@@ -157,10 +150,10 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
|
||||
context 'with existing names in both languages' do
|
||||
let(:english_name) do
|
||||
create(:tag_name, name: 'shared_name', language_code: 'en', script_code: 'Latn')
|
||||
let(:ainu_name) do
|
||||
create(:tag_name, name: 'shared_name', language_code: 'ain', script_code: 'Kana')
|
||||
end
|
||||
let(:english_tag) { create(:tag, primary_tag_name: english_name, category: :material) }
|
||||
let(:ainu_tag) { create(:tag, primary_tag_name: ainu_name, category: :material) }
|
||||
let(:nipponese_tag) do
|
||||
create(:tag, primary_name: 'temporary_nipponese', category: :general).tap do |tag|
|
||||
# Isolate lookup from the separately tested uniqueness validation.
|
||||
@@ -168,173 +161,163 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
it 'plans and creates the post using the English identity and category' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'plans and creates the post using the Ainu identity and category' do
|
||||
locale
|
||||
english_tag
|
||||
ainu_tag
|
||||
nipponese_tag
|
||||
post '/posts', params: {
|
||||
locale: 'en', title: 'English identity',
|
||||
url: 'https://example.com/english-identity', tags: 'shared_name', parent_post_ids: '' }
|
||||
locale: 'ain-Kana', title: 'Ainu identity',
|
||||
url: 'https://example.com/ainu-identity', tags: 'shared_name', parent_post_ids: '' }
|
||||
|
||||
expect(response).to have_http_status(:created), response.body
|
||||
record = Post.find(json.fetch('id'))
|
||||
expect(record.tags).to include(english_tag)
|
||||
expect(record.tags).to include(ainu_tag)
|
||||
expect(record.tags).not_to include(nipponese_tag)
|
||||
expect(english_tag.reload.category).to eq('material')
|
||||
expect(ainu_tag.reload.category).to eq('material')
|
||||
expect(nipponese_tag.reload.category).to eq('general')
|
||||
end
|
||||
|
||||
it 'updates the post using the English identity' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'updates the post using the Ainu identity' do
|
||||
locale
|
||||
english_tag
|
||||
ainu_tag
|
||||
nipponese_tag
|
||||
record = create(:post)
|
||||
PostVersionRecorder.record!(post: record, event_type: :create, created_by_user: member)
|
||||
|
||||
put "/posts/#{ record.id }", params: {
|
||||
locale: 'en', title: record.title, tags: 'shared_name', parent_post_ids: '',
|
||||
locale: 'ain-Kana', title: record.title, tags: 'shared_name', parent_post_ids: '',
|
||||
base_version_no: record.reload.version_no }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(record.reload.tags).to include(english_tag)
|
||||
expect(record.reload.tags).to include(ainu_tag)
|
||||
expect(record.tags).not_to include(nipponese_tag)
|
||||
end
|
||||
|
||||
it 'resolves the English material tag' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'resolves the Ainu material tag' do
|
||||
locale
|
||||
english_tag
|
||||
ainu_tag
|
||||
nipponese_tag
|
||||
post '/materials', params: {
|
||||
locale: 'en', tag: 'shared_name', url: 'https://example.com/english-material' }
|
||||
locale: 'ain-Kana', tag: 'shared_name', url: 'https://example.com/ainu-material' }
|
||||
|
||||
expect(response).to have_http_status(:created), response.body
|
||||
expect(Material.find(json.fetch('id')).tag).to eq(english_tag)
|
||||
expect(Material.find(json.fetch('id')).tag).to eq(ainu_tag)
|
||||
expect(Material.where(tag: nipponese_tag)).to be_empty
|
||||
end
|
||||
|
||||
it 'resolves the English parent tag' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'resolves the Ainu parent tag' do
|
||||
locale
|
||||
english_tag
|
||||
ainu_tag
|
||||
nipponese_tag
|
||||
child = create(:tag)
|
||||
|
||||
put "/tags/#{ child.id }", params: {
|
||||
locale: 'en', name: primary_tag_name_for(child, 'ja').name,
|
||||
locale: 'ain-Kana', name: primary_tag_name_for(child, 'ja').name,
|
||||
category: child.category, deprecated: false,
|
||||
aliases: '', parent_tags: 'shared_name' }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(TagImplication.where(tag: child).pluck(:parent_tag_id)).to eq([english_tag.id])
|
||||
expect(TagImplication.where(tag: child).pluck(:parent_tag_id)).to eq([ainu_tag.id])
|
||||
end
|
||||
|
||||
it 'resolves the English internal tag for a Nico link' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'resolves the Ainu internal tag for a Nico link' do
|
||||
locale
|
||||
english_tag
|
||||
ainu_tag
|
||||
nipponese_tag
|
||||
external = create(:external_tag)
|
||||
NicoTagVersionRecorder.record!(
|
||||
external_tag: external, event_type: :create, created_by_user: member)
|
||||
|
||||
put "/tags/nico/#{ external.id }", params: { locale: 'en', tags: 'shared_name' }
|
||||
put "/tags/nico/#{ external.id }", params: { locale: 'ain-Kana', tags: 'shared_name' }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(external.reload.linked_tags).to contain_exactly(english_tag)
|
||||
expect(external.reload.linked_tags).to contain_exactly(ainu_tag)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when renaming or updating aliases in English' do
|
||||
let(:english_name) do
|
||||
create(:tag_name, name: 'english_original', language_code: 'en', script_code: 'Latn')
|
||||
context 'when renaming or updating aliases in Ainu' do
|
||||
let(:ainu_name) do
|
||||
create(:tag_name, name: 'ainu_original', language_code: 'ain', script_code: 'Kana')
|
||||
end
|
||||
let(:tag) { create(:tag, primary_tag_name: english_name) }
|
||||
let(:tag) { create(:tag, primary_tag_name: ainu_name) }
|
||||
|
||||
it 'marks a human-renamed generated primary as no longer auto-generated' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
generated_tag = create(:tag, primary_name: 'rename_generated_source')
|
||||
generated_name = primary_tag_name_for(generated_tag, 'en')
|
||||
generated_name = primary_tag_name_for(generated_tag, 'ain')
|
||||
expect(generated_name.auto_generated).to be(true)
|
||||
|
||||
patch "/tags/#{ generated_tag.id }", params: {
|
||||
locale: 'en', name: 'human_english_name' }
|
||||
locale: 'ain-Kana', name: 'human_ainu_name' }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(generated_name.reload).to have_attributes(
|
||||
name: 'human_english_name', auto_generated: false)
|
||||
name: 'human_ainu_name', auto_generated: false)
|
||||
end
|
||||
|
||||
it 'does not steal another tag primary for an alias' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
other_tag = create(:tag, primary_name: 'other_nipponese')
|
||||
other_primary = primary_tag_name_for(other_tag, 'en')
|
||||
other_primary.update!(name: 'other_english_primary', auto_generated: false)
|
||||
create(:tag_name, :alias, tag:, name: 'existing_english_alias',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
primary_name_before = primary_tag_name_for(tag, 'en').name
|
||||
other_primary = primary_tag_name_for(other_tag, 'ain')
|
||||
other_primary.update!(name: 'other_ainu_primary', auto_generated: false)
|
||||
create(:tag_name, :alias, tag:, name: 'existing_ainu_alias',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
primary_name_before = primary_tag_name_for(tag, 'ain').name
|
||||
aliases_before =
|
||||
tag.tag_names.where(language_code: 'en', primary_flg: false)
|
||||
tag.tag_names.where(language_code: 'ain', primary_flg: false)
|
||||
.order(:name).pluck(:name)
|
||||
category_before = tag.category
|
||||
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
locale: 'en', name: 'renamed_before_alias_collision',
|
||||
locale: 'ain-Kana', name: 'renamed_before_alias_collision',
|
||||
category: 'character', deprecated: false,
|
||||
aliases: 'other_english_primary', parent_tags: '' }
|
||||
aliases: 'other_ainu_primary', parent_tags: '' }
|
||||
|
||||
aggregate_failures do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(other_primary.reload).to have_attributes(
|
||||
tag_id: other_tag.id, language_code: 'en', primary_flg: true)
|
||||
expect(TagName.where(tag: other_tag, language_code: 'en', primary_flg: true))
|
||||
tag_id: other_tag.id, language_code: 'ain', primary_flg: true)
|
||||
expect(TagName.where(tag: other_tag, language_code: 'ain', primary_flg: true))
|
||||
.to contain_exactly(other_primary)
|
||||
expect(primary_tag_name_for(tag.reload, 'en').name).to eq(primary_name_before)
|
||||
expect(primary_tag_name_for(tag.reload, 'ain').name).to eq(primary_name_before)
|
||||
expect(tag.category).to eq(category_before)
|
||||
aliases_after =
|
||||
tag.tag_names.where(language_code: 'en', primary_flg: false)
|
||||
tag.tag_names.where(language_code: 'ain', primary_flg: false)
|
||||
.order(:name).pluck(:name)
|
||||
expect(aliases_after).to eq(aliases_before)
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows a rename to a name already used in Nipponese' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag, primary_name: 'rename_target')
|
||||
|
||||
patch "/tags/#{ tag.id }", params: { locale: 'en', name: 'rename_target' }
|
||||
patch "/tags/#{ tag.id }", params: { locale: 'ain-Kana', name: 'rename_target' }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(primary_tag_name_for(tag.reload, 'en')).to have_attributes(
|
||||
name: 'rename_target', language_code: 'en', tag_id: tag.id)
|
||||
expect(primary_tag_name_for(tag.reload, 'ain')).to have_attributes(
|
||||
name: 'rename_target', language_code: 'ain', tag_id: tag.id)
|
||||
expect(primary_tag_name_for(nipponese.reload, 'ja')).to have_attributes(
|
||||
name: 'rename_target', language_code: 'ja', tag_id: nipponese.id)
|
||||
end
|
||||
|
||||
it 'creates aliases in the requested language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
locale: 'en', name: english_name.name,
|
||||
locale: 'ain-Kana', name: ainu_name.name,
|
||||
category: tag.category, deprecated: false,
|
||||
aliases: 'english_alias', parent_tags: '' }
|
||||
aliases: 'ainu_alias', parent_tags: '' }
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(TagName.find_by!(language_code: 'en', name: 'english_alias'))
|
||||
expect(TagName.find_by!(language_code: 'ain', name: 'ainu_alias'))
|
||||
.to have_attributes(
|
||||
script_code: 'Latn',
|
||||
tag_id: tag.id, primary_flg: false, language_code: 'en')
|
||||
primary = TagName.find_by!(tag_id: tag.id, language_code: 'en', primary_flg: true)
|
||||
expect(primary).to have_attributes(name: 'english_original', script_code: 'Latn')
|
||||
script_code: 'Kana',
|
||||
tag_id: tag.id, primary_flg: false, language_code: 'ain')
|
||||
primary = TagName.find_by!(tag_id: tag.id, language_code: 'ain', primary_flg: true)
|
||||
expect(primary).to have_attributes(name: 'ainu_original', script_code: 'Kana')
|
||||
end
|
||||
|
||||
it 'does not take an alias from another language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag, primary_name: 'nipponese_owner')
|
||||
nipponese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
@@ -344,7 +327,7 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
primary_flg: false, language_code: 'ja')
|
||||
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
locale: 'en', name: english_name.name,
|
||||
locale: 'ain-Kana', name: ainu_name.name,
|
||||
category: tag.category, deprecated: false,
|
||||
aliases: 'shared_alias', parent_tags: '' }
|
||||
|
||||
@@ -352,12 +335,12 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
expect(nipponese_alias.reload).to have_attributes(
|
||||
tag_id: nipponese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(TagName.find_by!(language_code: 'en', name: 'shared_alias'))
|
||||
expect(TagName.find_by!(language_code: 'ain', name: 'shared_alias'))
|
||||
.to have_attributes(
|
||||
tag_id: tag.id, script_code: 'Latn',
|
||||
primary_flg: false, language_code: 'en')
|
||||
tag_id: tag.id, script_code: 'Kana',
|
||||
primary_flg: false, language_code: 'ain')
|
||||
expect(TagName.where(name: 'shared_alias').pluck(:language_code, :tag_id))
|
||||
.to contain_exactly(['ja', nipponese.id], ['en', tag.id])
|
||||
.to contain_exactly(['ja', nipponese.id], ['ain', tag.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
|
||||
it 'uses selected-language names in native collection and nested placements' do
|
||||
["/tag_groups/#{ group.id }", '/tag_groups'].each do |path|
|
||||
get path, params: { locale: 'ain' }
|
||||
get path, params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
representation = json.is_a?(Array) ? json.sole : json
|
||||
expect(representation.fetch('members').sole.fetch('tag').fetch('name'))
|
||||
@@ -37,14 +37,14 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
it 'uses snapshot names recursively for history and current names for the latest view' do
|
||||
version = group.versions.sole
|
||||
ainu_name.update!(name: 'renamed_ainu')
|
||||
get "/wiki/#{ group.id }", params: { locale: 'ain' }
|
||||
get "/wiki/#{ group.id }", params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('body')).to include('renamed_ainu')
|
||||
get "/wiki/#{ group.id }", params: { locale: 'ain', version: version.id }
|
||||
get "/wiki/#{ group.id }", params: { locale: 'ain-Kana', version: version.id }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('body').scan('ainu_member').length).to eq(2)
|
||||
expect(json.fetch('body')).not_to include('renamed_ainu', 'japanese_member')
|
||||
get "/wiki/#{ group.id }/diff", params: { locale: 'ain', from: version.id }
|
||||
get "/wiki/#{ group.id }/diff", params: { locale: 'ain-Kana', from: version.id }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('diff').map { _1.fetch('type') }.uniq).to eq(['context'])
|
||||
end
|
||||
@@ -52,23 +52,24 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
['タググループ:', 'tag_group:', 'TAG_GROUP:'].each do |prefix|
|
||||
it "round trips #{ prefix } through create, lookup, search and update" do
|
||||
post '/wiki', params: {
|
||||
locale: 'ain', title: "#{ prefix }parent", body: '- tag_group:locale group' },
|
||||
locale: 'ain-Kana', title: "#{ prefix }parent", body: '- tag_group:locale group' },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:created)
|
||||
id = json.fetch('id')
|
||||
expect(json.fetch('body')).to include('タググループ:locale group')
|
||||
path = "/wiki/title/#{ CGI.escapeURIComponent("#{ prefix }parent") }"
|
||||
get path, params: { locale: 'ain' }
|
||||
get path, params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('id')).to eq(id)
|
||||
get "#{ path }/exists", params: { locale: 'ain' }
|
||||
get "#{ path }/exists", params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:no_content)
|
||||
get '/wiki/search', params: { locale: 'ain', title: "#{ prefix }parent" }
|
||||
get '/wiki/search', params: { locale: 'ain-Kana', title: "#{ prefix }parent" }
|
||||
expect(json.map { _1.fetch('id') }).to eq([id])
|
||||
put "/wiki/#{ id }", params: {
|
||||
locale: 'ain', title: "#{ prefix }renamed", body: '- ainu_member' }, headers: headers
|
||||
locale: 'ain-Kana', title: "#{ prefix }renamed", body: '- ainu_member' },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
get "/tag_groups/#{ id }", params: { locale: 'ain' }
|
||||
get "/tag_groups/#{ id }", params: { locale: 'ain-Kana' }
|
||||
expect(json.fetch('members').sole.fetch('tag').fetch('name')).to eq('ainu_member')
|
||||
end
|
||||
end
|
||||
@@ -81,7 +82,7 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
end.to raise_error(TagGroupMarkdownParser::InvalidDocument)
|
||||
before_state = group_state
|
||||
put "/wiki/#{ group.id }", params: {
|
||||
locale: 'ain', title: 'タググループ:partial rename', body: '- japanese_member' },
|
||||
locale: 'ain-Kana', title: 'タググループ:partial rename', body: '- japanese_member' },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(group_state).to eq(before_state)
|
||||
@@ -89,15 +90,15 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
|
||||
it 'passes locale into native validation and facade compatibility checks' do
|
||||
post '/tag_groups', params: {
|
||||
locale: 'ain', name: 'native', description: nil, members:, placements: },
|
||||
locale: 'ain-Kana', name: 'native', description: nil, members:, placements: },
|
||||
headers:, as: :json
|
||||
expect(response).to have_http_status(:created)
|
||||
id = json.fetch('id')
|
||||
expect(json.fetch('members').sole.fetch('tag').fetch('name')).to eq('ainu_member')
|
||||
get "/wiki/#{ id }", params: { locale: 'ain' }
|
||||
get "/wiki/#{ id }", params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
body = json.fetch('body')
|
||||
put "/wiki/#{ id }", params: { locale: 'ain', title: 'tag_group:native', body: },
|
||||
put "/wiki/#{ id }", params: { locale: 'ain-Kana', title: 'tag_group:native', body: },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(TagGroup.find(id).version_no).to eq(1)
|
||||
@@ -115,7 +116,7 @@ RSpec.describe 'Tag group locale contracts', type: :request do
|
||||
representation = TagGroupRepr.historical(ainu_locale, version)
|
||||
expect(representation.fetch('members').sole.fetch('tag').fetch('name')).to be_nil
|
||||
expect(representation.fetch('placements').sole.fetch('tag').fetch('name')).to be_nil
|
||||
get "/wiki/#{ old_group.id }", params: { locale: 'ain', version: version.id }
|
||||
get "/wiki/#{ old_group.id }", params: { locale: 'ain-Kana', version: version.id }
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(response.body).not_to include('historical_japanese', 'current_ainu')
|
||||
end
|
||||
|
||||
@@ -20,12 +20,12 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
|
||||
['/wiki', '/wiki/search'].each do |path|
|
||||
it "filters #{ path } by the selected language" do
|
||||
get path, params: { locale: 'ain' }
|
||||
get path, params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.map { _1.fetch('id') }).to eq([ainu.id])
|
||||
expect(json.sole).to include('title' => 'ainu_title', 'body' => 'Ainu body')
|
||||
|
||||
get path, params: { locale: 'ain', title: 'japanese' }
|
||||
get path, params: { locale: 'ain-Kana', title: 'japanese' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json).to eq([])
|
||||
end
|
||||
@@ -39,17 +39,17 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
|
||||
it 'resolves titles and aliases only in the selected language in both APIs' do
|
||||
['/wiki/title/japanese_title', '/tags/name/japanese_title/description'].each do |path|
|
||||
get path, params: { locale: 'ain' }
|
||||
get path, params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
['/wiki/title/ainu_title', '/tags/name/ainu_title/description'].each do |path|
|
||||
get path, params: { locale: 'ain' }
|
||||
get path, params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('body')).to eq('Ainu body')
|
||||
end
|
||||
get '/wiki/title/ainu_title/exists', params: { locale: 'ain' }
|
||||
get '/wiki/title/ainu_title/exists', params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:no_content)
|
||||
get '/wiki/title/japanese_title/exists', params: { locale: 'ain' }
|
||||
get '/wiki/title/japanese_title/exists', params: { locale: 'ain-Kana' }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
|
||||
@@ -57,14 +57,14 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
revision = current_description_version(japanese)
|
||||
["/wiki/#{ japanese.id }", "/wiki/#{ japanese.id }/exists",
|
||||
"/wiki/#{ japanese.id }/diff"].each do |path|
|
||||
get path, params: { locale: 'ain', from: revision.id }
|
||||
get path, params: { locale: 'ain-Kana', from: revision.id }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
expect(response.body).not_to include('Japanese body')
|
||||
end
|
||||
get '/wiki/changes', params: { locale: 'ain', id: japanese.id }
|
||||
get '/wiki/changes', params: { locale: 'ain-Kana', id: japanese.id }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json).to eq([])
|
||||
get '/wiki/changes', params: { locale: 'ain' }
|
||||
get '/wiki/changes', params: { locale: 'ain-Kana' }
|
||||
expect(json.map { _1.fetch('revision_id') })
|
||||
.to eq([current_description_version(ainu).id])
|
||||
end
|
||||
@@ -73,7 +73,7 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
snapshot = [japanese.attributes, ainu.attributes, ainu_name.attributes]
|
||||
expect do
|
||||
put "/wiki/#{ japanese.id }", params: {
|
||||
locale: 'ain', title: 'renamed', body: 'wrong target' }, headers: headers
|
||||
locale: 'ain-Kana', title: 'renamed', body: 'wrong target' }, headers: headers
|
||||
end.not_to change(TagDescriptionVersion, :count)
|
||||
expect(response).to have_http_status(:not_found)
|
||||
expect([japanese.reload.attributes, ainu.reload.attributes, ainu_name.reload.attributes])
|
||||
@@ -89,10 +89,10 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
snapshot = original.attributes
|
||||
expect do
|
||||
if api == :wiki
|
||||
post '/wiki', params: { locale: 'ain', title: 'other_ainu', body: 'created' },
|
||||
post '/wiki', params: { locale: 'ain-Kana', title: 'other_ainu', body: 'created' },
|
||||
headers: headers
|
||||
else
|
||||
put "/tags/#{ other.id }/description", params: { locale: 'ain', body: 'created' },
|
||||
put "/tags/#{ other.id }/description", params: { locale: 'ain-Kana', body: 'created' },
|
||||
headers: headers
|
||||
end
|
||||
end.to change(TagDescription, :count).by(1)
|
||||
@@ -108,20 +108,20 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
it 'shares selected-language edits and revision identity across both APIs' do
|
||||
snapshot = japanese.attributes
|
||||
first = current_description_version(ainu)
|
||||
put "/tags/#{ tag.id }/description", params: { locale: 'ain', body: 'native edit' },
|
||||
put "/tags/#{ tag.id }/description", params: { locale: 'ain-Kana', body: 'native edit' },
|
||||
headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
second = current_description_version(ainu)
|
||||
expect(second).to have_attributes(language_code: 'ain', version_no: 2)
|
||||
expect(second.id).not_to eq(first.id)
|
||||
get "/wiki/#{ ainu.id }", params: { locale: 'ain' }
|
||||
get "/wiki/#{ ainu.id }", params: { locale: 'ain-Kana' }
|
||||
expect(json).to include('body' => 'native edit', 'revision_id' => second.id)
|
||||
|
||||
put "/wiki/#{ ainu.id }", params: {
|
||||
locale: 'ain', title: 'ainu_title', body: 'facade edit',
|
||||
locale: 'ain-Kana', title: 'ainu_title', body: 'facade edit',
|
||||
base_revision_id: second.id }, headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
get "/tags/#{ tag.id }/description", params: { locale: 'ain' }
|
||||
get "/tags/#{ tag.id }/description", params: { locale: 'ain-Kana' }
|
||||
expect(json).to include('body' => 'facade edit', 'language_code' => 'ain', 'version_no' => 3)
|
||||
expect(japanese.reload.attributes).to eq(snapshot)
|
||||
end
|
||||
@@ -133,7 +133,7 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
snapshot = [ainu.reload.attributes, ainu_name.attributes, japanese.attributes]
|
||||
expect do
|
||||
put "/wiki/#{ ainu.id }", params: {
|
||||
locale: 'ain', title: 'conflicting_name', body: 'current',
|
||||
locale: 'ain-Kana', title: 'conflicting_name', body: 'current',
|
||||
base_revision_id: stale.id }, headers: headers
|
||||
end.to change(TagDescriptionVersion, :count).by(0).and change(TagVersion, :count).by(0)
|
||||
expect(response).to have_http_status(:conflict)
|
||||
@@ -145,14 +145,14 @@ RSpec.describe 'Wiki and native API locale contracts', type: :request do
|
||||
first = current_description_version(ainu)
|
||||
TagDescriptionOperation.update!(
|
||||
ainu_locale, tag:, body: 'later', updated_by_user: user)
|
||||
get "/wiki/#{ ainu.id }", params: { locale: 'ain', version: first.id }
|
||||
get "/wiki/#{ ainu.id }", params: { locale: 'ain-Kana', version: first.id }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json).to include('body' => 'Ainu body', 'revision_id' => first.id)
|
||||
get "/wiki/#{ ainu.id }/diff", params: { locale: 'ain', from: first.id }
|
||||
get "/wiki/#{ ainu.id }/diff", params: { locale: 'ain-Kana', from: first.id }
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.fetch('newer_revision_id')).to eq(current_description_version(ainu).id)
|
||||
get "/wiki/#{ ainu.id }/diff", params: {
|
||||
locale: 'ain', from: current_description_version(japanese).id }
|
||||
locale: 'ain-Kana', from: current_description_version(japanese).id }
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe PostBulkCreator do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'limits workers to two and keeps failures in their request slots' do
|
||||
locale = Locale.nipponese
|
||||
@@ -67,8 +67,7 @@ RSpec.describe PostBulkCreator do
|
||||
expect(results[3].dig(:post, :id)).to eq(4)
|
||||
end
|
||||
|
||||
it 'passes a future English locale to preflight and creation in every worker' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
it 'passes a future Ainu locale to preflight and creation in every worker' do
|
||||
locale
|
||||
actor = instance_double(User, id: 123)
|
||||
allow(User).to receive(:find).with(123).and_return(actor)
|
||||
|
||||
@@ -11,23 +11,22 @@ RSpec.describe PostCreatePlan do
|
||||
end
|
||||
|
||||
context 'with an explicit locale' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
it 'resolves the matching language identity and its parents' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
english_name = create(:tag_name, name: 'shared_name',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, primary_tag_name: english_name, category: :character)
|
||||
ainu_name = create(:tag_name, name: 'shared_name',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu = create(:tag, primary_tag_name: ainu_name, category: :character)
|
||||
nipponese = create(:tag, primary_name: 'temporary_nipponese', category: :general)
|
||||
# The DB permits this identity; validation has its own contract spec.
|
||||
primary_tag_name_for(nipponese, 'ja').update_columns(name: 'shared_name')
|
||||
english_parent_name = create(:tag_name, name: 'english_parent',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english_parent = create(:tag, primary_tag_name: english_parent_name,
|
||||
ainu_parent_name = create(:tag_name, name: 'ainu_parent',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu_parent = create(:tag, primary_tag_name: ainu_parent_name,
|
||||
category: :material)
|
||||
nipponese_parent = create(:tag, primary_name: 'nipponese_parent', category: :general)
|
||||
TagImplication.create!(tag: english, parent_tag: english_parent)
|
||||
TagImplication.create!(tag: ainu, parent_tag: ainu_parent)
|
||||
TagImplication.create!(tag: nipponese, parent_tag: nipponese_parent)
|
||||
|
||||
plan = described_class.new(attributes: { tags: 'shared_name' }).build!(locale)
|
||||
@@ -35,35 +34,34 @@ RSpec.describe PostCreatePlan do
|
||||
expect(plan[:direct_tag_specs]).to eq(
|
||||
[{ name: 'shared_name', category: :character }])
|
||||
expect(plan[:post_tag_specs]).to include(
|
||||
{ name: primary_tag_name_for(english_parent, 'en').name, category: :material })
|
||||
{ name: primary_tag_name_for(ainu_parent, 'ain').name, category: :material })
|
||||
expect(plan[:post_tag_specs].pluck(:name))
|
||||
.not_to include(primary_tag_name_for(nipponese_parent, 'ja').name)
|
||||
end
|
||||
|
||||
it 'resolves aliases within the requested language' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
nipponese = create(:tag, primary_name: 'nipponese_canonical')
|
||||
english_name = create(:tag_name, name: 'english_canonical',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, primary_tag_name: english_name, category: :character)
|
||||
ainu_name = create(:tag_name, name: 'ainu_canonical',
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
ainu = create(:tag, primary_tag_name: ainu_name, category: :character)
|
||||
nipponese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: nipponese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
ainu_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: ainu,
|
||||
language_code: 'ain', script_code: 'Kana')
|
||||
|
||||
expect(nipponese_alias.reload).to have_attributes(
|
||||
tag_id: nipponese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(ainu_alias.reload).to have_attributes(
|
||||
tag_id: ainu.id,
|
||||
primary_flg: false, language_code: 'ain')
|
||||
|
||||
plan = described_class.new(attributes: { tags: 'shared_alias' }).build!(locale)
|
||||
|
||||
expect(plan[:direct_tag_specs]).to eq(
|
||||
[{ name: english_name.name, category: :character }])
|
||||
[{ name: ainu_name.name, category: :character }])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -77,11 +77,10 @@ RSpec.describe PostCreator do
|
||||
end
|
||||
|
||||
context 'with an explicit locale' do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
[false, true].each do |planned|
|
||||
it "passes locale to tag creation with planned attributes: #{ planned }" do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
locale
|
||||
attributes = {
|
||||
title: 'Locale propagation',
|
||||
@@ -97,8 +96,8 @@ RSpec.describe PostCreator do
|
||||
|
||||
expect(Tag).to have_received(:find_or_create_by_tag_name!)
|
||||
.with(locale, 'locale_character', category: :character).at_least(:once)
|
||||
tag_name = TagName.find_by!(language_code: 'en', name: 'locale_character')
|
||||
expect(tag_name).to have_attributes(script_code: 'Latn', primary_flg: true)
|
||||
tag_name = TagName.find_by!(language_code: 'ain', name: 'locale_character')
|
||||
expect(tag_name).to have_attributes(script_code: 'Kana', primary_flg: true)
|
||||
expect(post.tags).to include(tag_name.tag)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagNameCompletion do
|
||||
let!(:language) { Language.create!(code: 'ain', name: 'ain') }
|
||||
let!(:script) { Script.create!(code: 'Kana', name: 'Kana') }
|
||||
let(:locale) do
|
||||
Locale.create!(code: 'ain-Kana', language_code: 'ain', script_code: 'Kana',
|
||||
region_code: 392, variants: '', name: 'ain-Kana')
|
||||
end
|
||||
|
||||
it 'generates a phonetic primary with the required identity and provenance' do
|
||||
tag = create(:tag, primary_name: '漢字あカ')
|
||||
|
||||
locale
|
||||
|
||||
expect(tag.reload.tag_name('ain')).to have_attributes(
|
||||
name: 'カンチ_ア_カ', language_code: 'ain', script_code: 'Kana',
|
||||
primary_flg: true, auto_generated: true, tag_id: tag.id)
|
||||
end
|
||||
|
||||
it 'uses the exact fallback when the input cannot be converted' do
|
||||
tag = create(:tag, primary_name: '😀')
|
||||
|
||||
locale
|
||||
|
||||
expect(tag.reload.name('ain')).to eq("Tag_##{ tag.id }")
|
||||
end
|
||||
|
||||
it 'uses the exact fallback when a generated name collides with a human name' do
|
||||
other = create(:tag, primary_name: 'other')
|
||||
create(:tag_name, tag: other, name: 'AbC', language_code: 'ain', script_code: 'Kana')
|
||||
tag = create(:tag, primary_name: 'AbC')
|
||||
|
||||
locale
|
||||
|
||||
expect(tag.reload.name('ain')).to eq("Tag_##{ tag.id }")
|
||||
expect(other.reload.name('ain')).to eq('AbC')
|
||||
end
|
||||
|
||||
it 'uses the exact fallback for a transcription that fails name validation' do
|
||||
tag = create(:tag, primary_name: 'base')
|
||||
source = TagName.new(name: 'nico:invalid', language_code: 'ja')
|
||||
|
||||
expect(TagName.generate_name(locale, tag, source)).to eq("Tag_##{ tag.id }")
|
||||
end
|
||||
|
||||
it 'preserves human confirmation and is idempotent across repeated completion' do
|
||||
locale
|
||||
tag = Tag.find_or_create_by_tag_name!(Locale.nipponese, 'あいぬ', category: :general)
|
||||
primary = tag.tag_name('ain')
|
||||
primary.update!(name: 'human_confirmed', auto_generated: false)
|
||||
snapshot = tag.tag_names.order(:id).map(&:attributes)
|
||||
|
||||
2.times { described_class.for_tag!(tag) }
|
||||
|
||||
expect(tag.tag_names.order(:id).map(&:attributes)).to eq(snapshot)
|
||||
end
|
||||
|
||||
it 'creates one primary per active language through the production creation path' do
|
||||
locale
|
||||
|
||||
tag = Tag.find_or_create_by_tag_name!(Locale.nipponese, 'アイヌ', category: :general)
|
||||
|
||||
expect(tag.tag_names.where(primary_flg: true).pluck(:language_code, :name))
|
||||
.to contain_exactly(['ja', 'アイヌ'], ['ain', 'アイヌ'])
|
||||
expect(Tag.find_or_create_by_tag_name!(locale, 'アイヌ', category: :general)).to eq(tag)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagNameTranscription do
|
||||
{
|
||||
'AbCdXYZ' => 'AbCdXYZ',
|
||||
'あいぬ' => 'アイヌ',
|
||||
'アイヌ' => 'アイヌ',
|
||||
'日本語' => 'ニチホンコ',
|
||||
'漢字' => 'カンチ',
|
||||
'漢あカ' => 'カン_ア_カ',
|
||||
'漢字あいうカナ' => 'カンチ_アイウ_カナ',
|
||||
'Ab漢あカZ' => 'Abカン_ア_カZ',
|
||||
'りゃリュリョ' => 'リヤ_リユリヨ',
|
||||
'キャット' => 'キヤット',
|
||||
'コーヒー' => 'コヒ',
|
||||
'コウコオケイケエカア' => 'コウコオケイケエカア',
|
||||
'ガギグゲゴダヂヅデド' => 'カキクケコタチチュテト',
|
||||
'バビブベボパピプペポ' => 'パピプペポパピプペポ',
|
||||
'ザジズゼゾ' => 'チャチチュチェチョ',
|
||||
'ジャジュジョ' => 'チヤチユチヨ',
|
||||
'アㇰアㇱアッアンアㇺアㇷ゚' => 'アㇰアㇱアッアンアㇺアㇷ゚',
|
||||
'アㇻイㇼウㇽエㇾオㇿ' => 'アㇻイㇼウㇽエㇾオㇿ',
|
||||
'漢Aあ' => 'カンAア' }.each do |source, expected|
|
||||
it "transcribes #{ source } as #{ expected }" do
|
||||
expect(described_class.ainu(source)).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
['😀', 'ヴ', 'ティ', 'ㇵ', '魑', '𠮷', 'ー', '々'].each do |source|
|
||||
it "rejects unsupported input #{ source }" do
|
||||
expect { described_class.ainu(source) }.to raise_error(described_class::Unconvertible)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagVersionRecorder do
|
||||
include_context 'English locale'
|
||||
include_context 'Ainu locale'
|
||||
|
||||
let(:user) { create_member_user! }
|
||||
let!(:tag) { create(:tag, primary_name: '日本語名') }
|
||||
@@ -17,11 +17,11 @@ RSpec.describe TagVersionRecorder do
|
||||
{ 'name' => 'alias_z', 'script_code' => 'Jpan' }] }
|
||||
end
|
||||
|
||||
def prepare_english_names!
|
||||
def prepare_ainu_names!
|
||||
locale
|
||||
primary_tag_name_for(tag, 'en').update!(name: 'English name', auto_generated: false)
|
||||
create(:tag_name, :alias, tag:, language_code: 'en', script_code: 'Latn',
|
||||
name: 'English alias')
|
||||
primary_tag_name_for(tag, 'ain').update!(name: 'Ainu name', auto_generated: false)
|
||||
create(:tag_name, :alias, tag:, language_code: 'ain', script_code: 'Kana',
|
||||
name: 'Ainu alias')
|
||||
end
|
||||
|
||||
it 'snapshots the Nipponese primary and sorted aliases in grouped names' do
|
||||
@@ -62,35 +62,32 @@ RSpec.describe TagVersionRecorder do
|
||||
end
|
||||
|
||||
it 'snapshots future languages together without a request locale argument' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_names!
|
||||
prepare_ainu_names!
|
||||
|
||||
version = described_class.record!(tag:, event_type: :create, created_by_user: user)
|
||||
|
||||
expect(version.names).to eq(
|
||||
'ja' => nipponese_snapshot,
|
||||
'en' => { 'name' => 'English name', 'script_code' => 'Latn',
|
||||
'ain' => { 'name' => 'Ainu name', 'script_code' => 'Kana',
|
||||
'auto_generated' => false,
|
||||
'aliases' => [{ 'name' => 'English alias', 'script_code' => 'Latn' }] })
|
||||
'aliases' => [{ 'name' => 'Ainu alias', 'script_code' => 'Kana' }] })
|
||||
end
|
||||
|
||||
it 'creates a version for an English-only change and preserves prior names' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_names!
|
||||
it 'creates a version for an Ainu-only change and preserves prior names' do
|
||||
prepare_ainu_names!
|
||||
original = described_class.record!(tag:, event_type: :create, created_by_user: user)
|
||||
primary_tag_name_for(tag, 'en').update!(name: 'Renamed')
|
||||
primary_tag_name_for(tag, 'ain').update!(name: 'Renamed')
|
||||
|
||||
updated = described_class.record!(tag:, event_type: :update, created_by_user: user)
|
||||
|
||||
expect(updated.version_no).to eq(2)
|
||||
expect(original.reload.names.fetch('en')).to include('name' => 'English name')
|
||||
expect(updated.names.fetch('en')).to include('name' => 'Renamed')
|
||||
expect(original.reload.names.fetch('ain')).to include('name' => 'Ainu name')
|
||||
expect(updated.names.fetch('ain')).to include('name' => 'Renamed')
|
||||
expect(updated.names.fetch('ja')).to eq(nipponese_snapshot)
|
||||
end
|
||||
|
||||
it 'does not create a version for an unchanged multilingual snapshot' do
|
||||
pending '日本語以外の Locale 有効化は別課題で実装する'
|
||||
prepare_english_names!
|
||||
prepare_ainu_names!
|
||||
described_class.record!(tag:, event_type: :create, created_by_user: user)
|
||||
|
||||
unchanged = described_class.record!(tag:, event_type: :update, created_by_user: user)
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
RSpec.shared_context 'Ainu locale contract' do
|
||||
let(:ainu_locale) { instance_double(Locale, language_code: 'ain', script_code: 'Jpan') }
|
||||
let(:ainu_locale) do
|
||||
instance_double(Locale, language_code: 'ain', script_code: 'Kana', deprecated_at: nil)
|
||||
end
|
||||
|
||||
before do
|
||||
# Only the foreign-key reference is seeded; no Locale or enum is enabled.
|
||||
# Keep description contracts independent of locale activation and backfill.
|
||||
Language.connection.execute(<<~SQL)
|
||||
INSERT IGNORE INTO languages (code, name, created_at)
|
||||
VALUES ('ain', 'Ainu', CURRENT_TIMESTAMP)
|
||||
SQL
|
||||
Script.find_or_create_by!(code: 'Kana') { _1.name = 'Kana' }
|
||||
allow(Locale).to receive(:find_by).and_call_original
|
||||
allow(Locale).to receive(:find_by).with(code: 'ain').and_return(ainu_locale)
|
||||
allow(Locale).to receive(:find_by).with(code: 'ain-Kana').and_return(ainu_locale)
|
||||
end
|
||||
|
||||
def add_ainu_name tag, name
|
||||
TagName.insert_all!([{
|
||||
tag_id: tag.id, language_code: 'ain', script_code: 'Jpan', name:,
|
||||
tag_id: tag.id, language_code: 'ain', script_code: 'Kana', name:,
|
||||
primary_flg: true, auto_generated: false,
|
||||
created_at: Time.current, updated_at: Time.current }])
|
||||
tag.tag_names.reset
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
RSpec.shared_context 'English locale' do
|
||||
def prepare_english_reference!
|
||||
Language.find_or_create_by!(code: 'en') { _1.name = 'English' }
|
||||
Script.find_or_create_by!(code: 'Latn') { _1.name = 'Latin' }
|
||||
region_class = Class.new(ApplicationRecord) { self.table_name = 'regions' }
|
||||
region_class.find_or_create_by!(code: 826) do |record|
|
||||
record.alpha_code = 'GB'
|
||||
record.name = 'United Kingdom'
|
||||
end
|
||||
RSpec.shared_context 'Ainu locale' do
|
||||
def prepare_ainu_reference!
|
||||
Language.find_or_create_by!(code: 'ain') { _1.name = 'ain' }
|
||||
Script.find_or_create_by!(code: 'Kana') { _1.name = 'Kana' }
|
||||
end
|
||||
|
||||
let(:locale) do
|
||||
prepare_english_reference!
|
||||
Locale.find_or_create_by!(code: 'en') do |record|
|
||||
record.language_code = 'en'
|
||||
record.script_code = 'Latn'
|
||||
record.region_code = 826
|
||||
prepare_ainu_reference!
|
||||
Locale.find_or_create_by!(code: 'ain-Kana') do |record|
|
||||
record.language_code = 'ain'
|
||||
record.script_code = 'Kana'
|
||||
record.region_code = 392
|
||||
record.variants = ''
|
||||
record.name = 'English'
|
||||
record.name = 'Ainu'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする