Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/amo/components/Addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export class AddonBase extends React.Component {

return (
<ShowMoreCard
header={i18n.sprintf(i18n.gettext('About this %(addonType)s'), { addonType })}
header={i18n.sprintf(i18n.gettext('About this %(addonType)s'), { addonType: i18n.addonType(addonType) })}
className="AddonDescription"
>
<div
Expand Down
40 changes: 6 additions & 34 deletions src/amo/components/RatingManager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@ import { setReview } from 'amo/actions/reviews';
import { getLatestUserReview, submitReview } from 'amo/api';
import DefaultAddonReview from 'amo/components/AddonReview';
import DefaultAuthenticateButton from 'core/components/AuthenticateButton';
import {
ADDON_TYPE_DICT,
ADDON_TYPE_EXTENSION,
ADDON_TYPE_LANG,
ADDON_TYPE_OPENSEARCH,
ADDON_TYPE_THEME,
validAddonTypes as defaultValidAddonTypes,
} from 'core/constants';
import translate from 'core/i18n/translate';
import log from 'core/logger';
import DefaultRating from 'ui/components/Rating';
Expand Down Expand Up @@ -111,33 +103,13 @@ export class RatingManagerBase extends React.Component {
});
}

getLogInPrompt(
{ addonType }: {| addonType: string |},
{
validAddonTypes = defaultValidAddonTypes,
}: {|
validAddonTypes: typeof defaultValidAddonTypes,
|} = {}
) {
getLogInPrompt({ addonType }: {| addonType: string |}) {
const { i18n } = this.props;
switch (addonType) {
case ADDON_TYPE_DICT:
return i18n.gettext('Log in to rate this dictionary');
case ADDON_TYPE_LANG:
return i18n.gettext('Log in to rate this language pack');
case ADDON_TYPE_OPENSEARCH:
return i18n.gettext('Log in to rate this search plugin');
case ADDON_TYPE_THEME:
return i18n.gettext('Log in to rate this theme');
case ADDON_TYPE_EXTENSION:
return i18n.gettext('Log in to rate this extension');
default:
if (!validAddonTypes.includes(addonType)) {
throw new Error(`Unknown extension type: ${addonType}`);
}
log.warn(`Using generic prompt for add-on type: ${addonType}`);
return i18n.gettext('Log in to rate this add-on');
}

return i18n.sprintf(
i18n.gettext('Log in to rate this %(addonType)s'),
{ addonType: i18n.addonType(addonType) }
);
}

renderLogInToRate() {
Expand Down
33 changes: 33 additions & 0 deletions src/core/i18n/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import Jed from 'jed';
import moment from 'moment';

import log from 'core/logger';
import {
ADDON_TYPE_COMPLETE_THEME,
ADDON_TYPE_DICT,
ADDON_TYPE_EXTENSION,
ADDON_TYPE_LANG,
ADDON_TYPE_OPENSEARCH,
ADDON_TYPE_THEME,
validAddonTypes,
} from 'core/constants';

const defaultLang = config.get('defaultLang');
const langs = config.get('langs');
Expand Down Expand Up @@ -287,6 +296,30 @@ export function makeI18n(
oneLineTranslationString(pluralKey), val);
};

// The `addonType` we use internally is not translated, so we use this helper
// to return translated add-on type names.
i18n.addonType = function addonType(type) {
switch (type) {
case ADDON_TYPE_DICT:
return i18n.gettext('dictionary');
case ADDON_TYPE_LANG:
return i18n.gettext('language pack');
case ADDON_TYPE_OPENSEARCH:
return i18n.gettext('search plugin');
case ADDON_TYPE_THEME:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just add case ADDON_TYPE_COMPLETE_THEME: here; as long as we "support" it we should return a value.

case ADDON_TYPE_COMPLETE_THEME:
return i18n.gettext('theme');
case ADDON_TYPE_EXTENSION:
return i18n.gettext('extension');
default:
if (!validAddonTypes.includes(type)) {
throw new Error(`Unknown extension type: ${type}`);
}
log.warn(`Using generic prompt for add-on type: ${type}`);
return i18n.gettext('add-on');
}
};

// We add a translated "moment" property to our `i18n` object
// to make translated date/time/etc. easy.
i18n.moment = moment;
Expand Down
32 changes: 31 additions & 1 deletion tests/unit/core/i18n/test_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import moment from 'moment';
import { oneLine } from 'common-tags';

import * as utils from 'core/i18n/utils';
import {
ADDON_TYPE_COMPLETE_THEME,
ADDON_TYPE_DICT,
ADDON_TYPE_EXTENSION,
ADDON_TYPE_LANG,
ADDON_TYPE_OPENSEARCH,
ADDON_TYPE_THEME,
} from 'core/constants';


const defaultLang = config.get('defaultLang');
Expand Down Expand Up @@ -394,7 +402,10 @@ describe('i18n utils', () => {
describe('makeI18n', () => {
class FakeJed {
constructor(i18nData) {
return i18nData;
return {
...i18nData,
gettext: (key) => key,
};
}
}

Expand Down Expand Up @@ -475,5 +486,24 @@ describe('i18n utils', () => {
sinon.assert.calledWith(toLocaleStringSpy, 'fr');
sinon.assert.notCalled(numberFormatSpy);
});

describe('addonType()', () => {
it('translates internal addon types', () => {
const i18n = utils.makeI18n({}, 'en', FakeJed);
expect(i18n.addonType(ADDON_TYPE_COMPLETE_THEME)).toEqual('theme');
expect(i18n.addonType(ADDON_TYPE_DICT)).toEqual('dictionary');
expect(i18n.addonType(ADDON_TYPE_EXTENSION)).toEqual('extension');
expect(i18n.addonType(ADDON_TYPE_LANG)).toEqual('language pack');
expect(i18n.addonType(ADDON_TYPE_OPENSEARCH)).toEqual('search plugin');
expect(i18n.addonType(ADDON_TYPE_THEME)).toEqual('theme');
});

it('throws an error if the given type is not valid', () => {
const i18n = utils.makeI18n({}, 'en', FakeJed);
expect(() => {
i18n.addonType('unknown-type');
}).toThrowError(/Unknown extension type/);
});
});
});
});