//  [java]
    public void translate(GeyserSession session, ServerTradeListPacket packet) {
        Inventory openInventory = session.getOpenInventory();
        if (!(openInventory instanceof MerchantContainer && openInventory.getId() == packet.getWindowId())) {
            return;
        }

        // Retrieve the fake villager involved in the trade, and update its metadata to match with the window information
        MerchantContainer merchantInventory = (MerchantContainer) openInventory;
        merchantInventory.setVillagerTrades(packet.getTrades());
        Entity villager = merchantInventory.getVillager();
        villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1);
        villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4);
        villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience());
        villager.updateBedrockMetadata(session);

        // Construct the packet that opens the trading window
        UpdateTradePacket updateTradePacket = new UpdateTradePacket();
        updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1);
        updateTradePacket.setContainerId((short) packet.getWindowId());
        updateTradePacket.setContainerType(ContainerType.TRADE);
        updateTradePacket.setDisplayName(openInventory.getTitle());
        updateTradePacket.setSize(0);
        updateTradePacket.setNewTradingUi(true);
        updateTradePacket.setUsingEconomyTrade(true);
        updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId());
        updateTradePacket.setTraderUniqueEntityId(villager.getGeyserId());

        NbtMapBuilder builder = NbtMap.builder();
        boolean addExtraTrade = packet.isRegularVillager() && packet.getVillagerLevel() < 5;
        List<NbtMap> tags = new ArrayList<>(addExtraTrade ? packet.getTrades().length + 1 : packet.getTrades().length);
        for (int i = 0; i < packet.getTrades().length; i++) {
            VillagerTrade trade = packet.getTrades()[i];
            NbtMapBuilder recipe = NbtMap.builder();
            recipe.putInt("netId", i + 1);
            recipe.putInt("maxUses", trade.isTradeDisabled() ? 0 : trade.getMaxUses());
            recipe.putInt("traderExp", trade.getXp());
            recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier());
            recipe.put("sell", getItemTag(session, trade.getOutput(), 0));
            recipe.putFloat("priceMultiplierB", 0.0f);
            recipe.putInt("buyCountB", trade.getSecondInput() != null ? trade.getSecondInput().getAmount() : 0);
            recipe.putInt("buyCountA", trade.getFirstInput().getAmount());
            recipe.putInt("demand", trade.getDemand());
            recipe.putInt("tier", packet.getVillagerLevel() > 0 ? packet.getVillagerLevel() - 1 : 0); // -1 crashes client
            recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice()));
            if (trade.getSecondInput() != null) {
                recipe.put("buyB", getItemTag(session, trade.getSecondInput(), 0));
            }
            recipe.putInt("uses", trade.getNumUses());
            recipe.putByte("rewardExp", (byte) 1);
            tags.add(recipe.build());
        }

        //Hidden trade to fix visual experience bug
        if (addExtraTrade) {
            tags.add(NbtMap.builder()
                    .putInt("maxUses", 0)
                    .putInt("traderExp", 0)
                    .putFloat("priceMultiplierA", 0.0f)
                    .putFloat("priceMultiplierB", 0.0f)
                    .putInt("buyCountB", 0)
                    .putInt("buyCountA", 0)
                    .putInt("demand", 0)
                    .putInt("tier", 5)
                    .putInt("uses", 0)
                    .putByte("rewardExp", (byte) 0)
                    .build());
        }

        builder.putList("Recipes", NbtType.COMPOUND, tags);

        List<NbtMap> expTags = new ArrayList<>(5);
        expTags.add(NbtMap.builder().putInt("0", 0).build());
        expTags.add(NbtMap.builder().putInt("1", 10).build());
        expTags.add(NbtMap.builder().putInt("2", 70).build());
        expTags.add(NbtMap.builder().putInt("3", 150).build());
        expTags.add(NbtMap.builder().putInt("4", 250).build());
        builder.putList("TierExpRequirements", NbtType.COMPOUND, expTags);

        updateTradePacket.setOffers(builder.build());
        session.sendUpstreamPacket(updateTradePacket);
    }