Skip to content
7 changes: 7 additions & 0 deletions .changeset/cute-humans-follow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@rocket.chat/model-typings': patch
'@rocket.chat/models': patch
'@rocket.chat/meteor': patch
---

Fixes auto-translate not activating for users who set their language preference after joining rooms
5 changes: 4 additions & 1 deletion apps/meteor/server/methods/saveUserPreferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,10 @@ export const saveUserPreferences = async (settings: Partial<UserPreferences>, us
}

if (language && oldLanguage !== language && rcSettings.get('AutoTranslate_AutoEnableOnJoinRoom')) {
const response = await Subscriptions.updateAllAutoTranslateLanguagesByUserId(user._id, language);
const workspaceLanguage = rcSettings.get('Language');
const targetLanguage = language === 'default' || language === workspaceLanguage ? null : language;

const response = await Subscriptions.setAutoTranslateByUserId(user._id, targetLanguage);
Comment thread
juliajforesti marked this conversation as resolved.
if (response.modifiedCount) {
void notifyOnSubscriptionChangedByAutoTranslateAndUserId(user._id);
}
Expand Down
90 changes: 90 additions & 0 deletions apps/meteor/tests/end-to-end/api/autotranslate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,96 @@ describe('AutoTranslate', () => {
expect(subscription).to.have.property('autoTranslateLanguage', 'es');
channelsToRemove.push(newChannel);
});

it('should enable autotranslate on existing subscriptions when user changes from workspace language to a different one', async () => {
await setLanguagePref('pt-BR', credA);
const newChannel = await createChannel(undefined, credA);
channelsToRemove.push(newChannel);

const subBefore = await getSub(newChannel._id, credA);
expect(subBefore).to.not.have.property('autoTranslate');
expect(subBefore).to.not.have.property('autoTranslateLanguage');

await setLanguagePref('en', credA);

const subAfter = await getSub(newChannel._id, credA);
expect(subAfter).to.have.property('autoTranslate', true);
expect(subAfter).to.have.property('autoTranslateLanguage', 'en');
});

it("should enable autotranslate on existing subscriptions when user changes from 'default' language to a non-workspace language", async () => {
await setLanguagePref('default', credA);
const newChannel = await createChannel(undefined, credA);
channelsToRemove.push(newChannel);

const subBefore = await getSub(newChannel._id, credA);
expect(subBefore).to.not.have.property('autoTranslate');
expect(subBefore).to.not.have.property('autoTranslateLanguage');

await setLanguagePref('en', credA);

const subAfter = await getSub(newChannel._id, credA);
expect(subAfter).to.have.property('autoTranslate', true);
expect(subAfter).to.have.property('autoTranslateLanguage', 'en');
});

it('should disable autotranslate on existing subscriptions when user changes language to default', async () => {
await setLanguagePref('en', credA);
const newChannel = await createChannel(undefined, credA);
channelsToRemove.push(newChannel);

const subBefore = await getSub(newChannel._id, credA);
expect(subBefore).to.have.property('autoTranslate', true);
Comment thread
juliajforesti marked this conversation as resolved.

await setLanguagePref('default', credA);

const subAfter = await getSub(newChannel._id, credA);
expect(subAfter).to.not.have.property('autoTranslate');
expect(subAfter).to.not.have.property('autoTranslateLanguage');
});

it('should disable autotranslate on existing subscriptions when user changes language to the workspace default', async () => {
await setLanguagePref('en', credA);
const newChannel = await createChannel(undefined, credA);
channelsToRemove.push(newChannel);

const subBefore = await getSub(newChannel._id, credA);
expect(subBefore).to.have.property('autoTranslate', true);
Comment thread
juliajforesti marked this conversation as resolved.

await setLanguagePref('pt-BR', credA);

const subAfter = await getSub(newChannel._id, credA);
expect(subAfter).to.not.have.property('autoTranslate');
expect(subAfter).to.not.have.property('autoTranslateLanguage');
});

it('should not re-enable autotranslate for rooms where the user has explicitly opted out', async () => {
await updatePermission('auto-translate', ['admin', 'user']);

await setLanguagePref('en', credA);
const newChannel = await createChannel(undefined, credA);
channelsToRemove.push(newChannel);

const subEnabled = await getSub(newChannel._id, credA);
expect(subEnabled).to.have.property('autoTranslate', true);

await request
.post(api('autotranslate.saveSettings'))
.set(credA)
.send({ roomId: newChannel._id, field: 'autoTranslate', value: false, defaultLanguage: 'en' })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});

const subOptedOut = await getSub(newChannel._id, credA);
expect(subOptedOut).to.have.property('autoTranslate', false);

await setLanguagePref('es', credA);

const subAfterLangChange = await getSub(newChannel._id, credA);
expect(subAfterLangChange).to.have.property('autoTranslate', false);
Comment thread
juliajforesti marked this conversation as resolved.
});
});
});
});
2 changes: 1 addition & 1 deletion packages/model-typings/src/models/ISubscriptionsModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export interface ISubscriptionsModel extends IBaseModel<ISubscription> {
cachedFindByUserId(userId: string, options?: FindOptions<ISubscription>): FindCursor<ISubscription>;
updateAutoTranslateById(_id: string, autoTranslate: boolean): Promise<UpdateResult>;

updateAllAutoTranslateLanguagesByUserId(userId: IUser['_id'], language: string): Promise<UpdateResult | Document>;
setAutoTranslateByUserId(userId: IUser['_id'], language: string | null): Promise<UpdateResult | Document>;
findByAutoTranslateAndUserId(
userId: ISubscription['u']['_id'],
autoTranslate?: ISubscription['autoTranslate'],
Expand Down
30 changes: 16 additions & 14 deletions packages/models/src/models/Subscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,8 +707,8 @@ export class SubscriptionsRaw extends BaseRaw<ISubscription> implements ISubscri
};
} else {
update = {
$unset: {
autoTranslate: 1,
$set: {
autoTranslate: false,
},
};
}
Expand All @@ -723,19 +723,21 @@ export class SubscriptionsRaw extends BaseRaw<ISubscription> implements ISubscri
return this.findOneAndUpdate(query, update, { returnDocument: 'after' });
}

updateAllAutoTranslateLanguagesByUserId(userId: IUser['_id'], language: string): Promise<UpdateResult | Document> {
const query = {
'u._id': userId,
'autoTranslate': true,
};

const update: UpdateFilter<ISubscription> = {
$set: {
autoTranslateLanguage: language,
},
};
setAutoTranslateByUserId(userId: IUser['_id'], language: string | null): Promise<UpdateResult | Document> {
if (language) {
return Promise.all([
this.updateMany({ 'u._id': userId, 'autoTranslate': true }, { $set: { autoTranslateLanguage: language } }),
this.updateMany(
{ 'u._id': userId, 'autoTranslate': { $exists: false } },
{ $set: { autoTranslate: true, autoTranslateLanguage: language } },
),
]).then(([updateResult, enableResult]) => ({
...updateResult,
modifiedCount: updateResult.modifiedCount + enableResult.modifiedCount,
}));
}

return this.updateMany(query, update);
return this.updateMany({ 'u._id': userId, 'autoTranslate': true }, { $unset: { autoTranslate: 1, autoTranslateLanguage: 1 } });
}

findByAutoTranslateAndUserId(
Expand Down
Loading