|  | /*
  ==============================================================================
   This file is part of the JUCE library.
   Copyright (c) 2022 - Raw Material Software Limited
   JUCE is an open source library subject to commercial or open-source
   licensing.
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
   Agreement and JUCE Privacy Policy.
   End User License Agreement: www.juce.com/juce-7-licence
   Privacy Policy: www.juce.com/juce-privacy-policy
   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.
  ==============================================================================
*/
#pragma once
#include "../../Utility/Helpers/jucer_TranslationHelpers.h"
//==============================================================================
class TranslationToolComponent final : public Component
{
public:
    TranslationToolComponent()
        : editorOriginal (documentOriginal, nullptr),
          editorPre      (documentPre,      nullptr),
          editorPost     (documentPost,     nullptr),
          editorResult   (documentResult,   nullptr)
    {
        instructionsLabel.setText (
            "This utility converts translation files to/from a format that can be passed to automatic translation tools."
            "\n\n"
            "First, choose whether to scan the current project for all TRANS() macros, or "
            "pick an existing translation file to load:", dontSendNotification);
        addAndMakeVisible (instructionsLabel);
        label1.setText ("..then copy-and-paste this annotated text into Google Translate or some other translator:", dontSendNotification);
        addAndMakeVisible (label1);
        label2.setText ("...then, take the translated result and paste it into the box below:", dontSendNotification);
        addAndMakeVisible (label2);
        label3.setText ("Finally, click the 'Generate' button, and a translation file will be created below. "
                        "Remember to update its language code at the top!", dontSendNotification);
        addAndMakeVisible (label3);
        label4.setText ("If you load an existing file the already translated strings will be removed. Ensure this box is empty to create a fresh translation", dontSendNotification);
        addAndMakeVisible (label4);
        addAndMakeVisible (editorOriginal);
        addAndMakeVisible (editorPre);
        addAndMakeVisible (editorPost);
        addAndMakeVisible (editorResult);
        addAndMakeVisible (generateButton);
        generateButton.onClick = [this] { generate(); };
        addAndMakeVisible (scanProjectButton);
        scanProjectButton.onClick = [this] { scanProject(); };
        addAndMakeVisible (scanFolderButton);
        scanFolderButton.onClick = [this] { scanFolder(); };
        addAndMakeVisible (loadTranslationButton);
        loadTranslationButton.onClick = [this] { loadFile(); };
    }
    void paint (Graphics& g) override
    {
        g.fillAll (findColour (backgroundColourId));
    }
    void resized() override
    {
        const int m          = 6;
        const int textH      = 44;
        const int extraH     = (7 * textH);
        const int editorH    = (getHeight() - extraH) / 4;
        const int numButtons = 3;
        Rectangle<int> r (getLocalBounds().withTrimmedBottom (m));
        const int buttonWidth = r.getWidth() / numButtons;
        instructionsLabel.setBounds (r.removeFromTop (textH * 2).reduced (m));
        r.removeFromTop (m);
        Rectangle<int> r2 (r.removeFromTop (textH - (2 * m)));
        scanProjectButton    .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
        scanFolderButton     .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
        loadTranslationButton.setBounds (r2.reduced (m, 0));
        label1   .setBounds (r.removeFromTop (textH)  .reduced (m));
        editorPre.setBounds (r.removeFromTop (editorH).reduced (m, 0));
        label2    .setBounds (r.removeFromTop (textH)  .reduced (m));
        editorPost.setBounds (r.removeFromTop (editorH).reduced (m, 0));
        r2 = r.removeFromTop (textH);
        generateButton.setBounds (r2.removeFromRight (152).reduced (m));
        label3        .setBounds (r2.reduced (m));
        editorResult  .setBounds (r.removeFromTop (editorH).reduced (m, 0));
        label4        .setBounds (r.removeFromTop (textH).reduced (m));
        editorOriginal.setBounds (r.reduced (m, 0));
    }
private:
    //==============================================================================
    void generate()
    {
        StringArray preStrings  (TranslationHelpers::breakApart (documentPre.getAllContent()));
        StringArray postStrings (TranslationHelpers::breakApart (documentPost.getAllContent()));
        if (postStrings.size() != preStrings.size())
        {
            auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon,
                                                             TRANS ("Error"),
                                                             TRANS ("The pre- and post-translation text doesn't match!\n\n"
                                                                    "Perhaps it got mangled by the translator?"));
            messageBox = AlertWindow::showScopedAsync (options, nullptr);
            return;
        }
        const LocalisedStrings originalTranslation (documentOriginal.getAllContent(), false);
        documentResult.replaceAllContent (TranslationHelpers::createFinishedTranslationFile (preStrings, postStrings, originalTranslation));
    }
    void scanProject()
    {
        if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject())
        {
            setPreTranslationText (TranslationHelpers::getPreTranslationText (*project));
        }
        else
        {
            auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon,
                                                             "Translation Tool",
                                                             "This will only work when you have a project open!");
            messageBox = AlertWindow::showScopedAsync (options, nullptr);
        }
    }
    void scanFolder()
    {
        chooser = std::make_unique<FileChooser> ("Choose the root folder to search for the TRANS macros",
                                                 File(), "*");
        auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
        chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
        {
            if (fc.getResult() == File{})
                return;
            StringArray strings;
            TranslationHelpers::scanFolderForTranslations (strings, fc.getResult());
            setPreTranslationText (TranslationHelpers::mungeStrings (strings));
        });
    }
    void loadFile()
    {
        chooser = std::make_unique<FileChooser> ("Choose a translation file to load", File(), "*");
        auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
        chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
        {
            if (fc.getResult() == File{})
                return;
            const LocalisedStrings loadedStrings (fc.getResult(), false);
            documentOriginal.replaceAllContent (fc.getResult().loadFileAsString().trim());
            setPreTranslationText (TranslationHelpers::getPreTranslationText (loadedStrings));
        });
    }
    void setPreTranslationText (const String& text)
    {
        documentPre.replaceAllContent (text);
        editorPre.grabKeyboardFocus();
        editorPre.selectAll();
    }
    //==============================================================================
    CodeDocument documentOriginal, documentPre, documentPost, documentResult;
    CodeEditorComponent editorOriginal, editorPre, editorPost, editorResult;
    Label label1, label2, label3, label4;
    Label instructionsLabel;
    TextButton generateButton        { TRANS ("Generate") },
               scanProjectButton     { "Scan project for TRANS macros" },
               scanFolderButton      { "Scan folder for TRANS macros" },
               loadTranslationButton { "Load existing translation file..."};
    std::unique_ptr<FileChooser> chooser;
    ScopedMessageBox messageBox;
};
 |