So, by how you say they are 'practically' identical, the Category, Product and Reviews might differ in their fields? You could try and get create an inheritance hierarchy where they all inherit from some base, abstract Description-class and then use various mapping strategies to get that into the DB, but that does feel wrong to me too.
Have you considered a third option, a Table Translation that just contains a single piece of text to be translated? In other words, instead of having the unique key be (category/product/review_id, language_id)) which loads an object with multiple fields for your various translations, have it be (category/product/review_id, language_id, text_key)). Something like:
| (categoryId/productId/reviewId) | language_id | text_key | text |
|---|---|---|---|
| someId | en | title | BEST PRODUCT EVER |
| someId | en | description | I really like this product |
| someOtherId | de | title | Acme Staubsauger (Rot) |
When a User with locale 'en' loads the Product X, you just select every translation where id = productXId and language_id = 'en' and load it in a Map which your application can use. This way, a Review can have different fields that need to be translated without modifying the DB-Definition. Likewise, if at some point you decide a ProductDescription needs a new translatable text, you simply insert it into this table and you're good to go.
Optionally, the single Id column can be three columns with nullable foreign key constraints, if you want the enhanced correctness that gives. See this question for various ways you could do that, or alternatives.
Upsides:
Reviews, Categories and Products can diverge in terms of required translations with no impact on your DB. They might start out 'practically' identical, but that's not guaranteed, after all.
Similarly, if any future objects need translated texts, you can integrate them into the same solution too.
You save yourself the headache of doing class inheritance mapping/persisting
Downside:
Description Object means you might try to access a translation that doesn't exist, or misspell it and only find out at runtime when a text can't be translated.