The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #pragma once
  14. #include "../../Utility/Helpers/jucer_TranslationHelpers.h"
  15. //==============================================================================
  16. class TranslationToolComponent : public Component
  17. {
  18. public:
  19. TranslationToolComponent()
  20. : editorOriginal (documentOriginal, nullptr),
  21. editorPre (documentPre, nullptr),
  22. editorPost (documentPost, nullptr),
  23. editorResult (documentResult, nullptr)
  24. {
  25. instructionsLabel.setText (
  26. "This utility converts translation files to/from a format that can be passed to automatic translation tools."
  27. "\n\n"
  28. "First, choose whether to scan the current project for all TRANS() macros, or "
  29. "pick an existing translation file to load:", dontSendNotification);
  30. addAndMakeVisible (instructionsLabel);
  31. label1.setText ("..then copy-and-paste this annotated text into Google Translate or some other translator:", dontSendNotification);
  32. addAndMakeVisible (label1);
  33. label2.setText ("...then, take the translated result and paste it into the box below:", dontSendNotification);
  34. addAndMakeVisible (label2);
  35. label3.setText ("Finally, click the 'Generate' button, and a translation file will be created below. "
  36. "Remember to update its language code at the top!", dontSendNotification);
  37. addAndMakeVisible (label3);
  38. 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);
  39. addAndMakeVisible (label4);
  40. addAndMakeVisible (editorOriginal);
  41. addAndMakeVisible (editorPre);
  42. addAndMakeVisible (editorPost);
  43. addAndMakeVisible (editorResult);
  44. addAndMakeVisible (generateButton);
  45. generateButton.onClick = [this] { generate(); };
  46. addAndMakeVisible (scanProjectButton);
  47. scanProjectButton.onClick = [this] { scanProject(); };
  48. addAndMakeVisible (scanFolderButton);
  49. scanFolderButton.onClick = [this] { scanFolder(); };
  50. addAndMakeVisible (loadTranslationButton);
  51. loadTranslationButton.onClick = [this] { loadFile(); };
  52. }
  53. void paint (Graphics& g) override
  54. {
  55. g.fillAll (findColour (backgroundColourId));
  56. }
  57. void resized() override
  58. {
  59. const int m = 6;
  60. const int textH = 44;
  61. const int extraH = (7 * textH);
  62. const int editorH = (getHeight() - extraH) / 4;
  63. const int numButtons = 3;
  64. Rectangle<int> r (getLocalBounds().withTrimmedBottom (m));
  65. const int buttonWidth = r.getWidth() / numButtons;
  66. instructionsLabel.setBounds (r.removeFromTop (textH * 2).reduced (m));
  67. r.removeFromTop (m);
  68. Rectangle<int> r2 (r.removeFromTop (textH - (2 * m)));
  69. scanProjectButton .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
  70. scanFolderButton .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
  71. loadTranslationButton.setBounds (r2.reduced (m, 0));
  72. label1 .setBounds (r.removeFromTop (textH) .reduced (m));
  73. editorPre.setBounds (r.removeFromTop (editorH).reduced (m, 0));
  74. label2 .setBounds (r.removeFromTop (textH) .reduced (m));
  75. editorPost.setBounds (r.removeFromTop (editorH).reduced (m, 0));
  76. r2 = r.removeFromTop (textH);
  77. generateButton.setBounds (r2.removeFromRight (152).reduced (m));
  78. label3 .setBounds (r2.reduced (m));
  79. editorResult .setBounds (r.removeFromTop (editorH).reduced (m, 0));
  80. label4 .setBounds (r.removeFromTop (textH).reduced (m));
  81. editorOriginal.setBounds (r.reduced (m, 0));
  82. }
  83. private:
  84. //==============================================================================
  85. void generate()
  86. {
  87. StringArray preStrings (TranslationHelpers::breakApart (documentPre.getAllContent()));
  88. StringArray postStrings (TranslationHelpers::breakApart (documentPost.getAllContent()));
  89. if (postStrings.size() != preStrings.size())
  90. {
  91. AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
  92. TRANS("Error"),
  93. TRANS("The pre- and post-translation text doesn't match!\n\n"
  94. "Perhaps it got mangled by the translator?"));
  95. return;
  96. }
  97. const LocalisedStrings originalTranslation (documentOriginal.getAllContent(), false);
  98. documentResult.replaceAllContent (TranslationHelpers::createFinishedTranslationFile (preStrings, postStrings, originalTranslation));
  99. }
  100. void scanProject()
  101. {
  102. if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject())
  103. setPreTranslationText (TranslationHelpers::getPreTranslationText (*project));
  104. else
  105. AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool",
  106. "This will only work when you have a project open!");
  107. }
  108. void scanFolder()
  109. {
  110. chooser = std::make_unique<FileChooser> ("Choose the root folder to search for the TRANS macros",
  111. File(), "*");
  112. auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
  113. chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
  114. {
  115. if (fc.getResult() == File{})
  116. return;
  117. StringArray strings;
  118. TranslationHelpers::scanFolderForTranslations (strings, fc.getResult());
  119. setPreTranslationText (TranslationHelpers::mungeStrings(strings));
  120. });
  121. }
  122. void loadFile()
  123. {
  124. chooser = std::make_unique<FileChooser> ("Choose a translation file to load", File(), "*");
  125. auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
  126. chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
  127. {
  128. if (fc.getResult() == File{})
  129. return;
  130. const LocalisedStrings loadedStrings (fc.getResult(), false);
  131. documentOriginal.replaceAllContent (fc.getResult().loadFileAsString().trim());
  132. setPreTranslationText (TranslationHelpers::getPreTranslationText (loadedStrings));
  133. });
  134. }
  135. void setPreTranslationText (const String& text)
  136. {
  137. documentPre.replaceAllContent (text);
  138. editorPre.grabKeyboardFocus();
  139. editorPre.selectAll();
  140. }
  141. //==============================================================================
  142. CodeDocument documentOriginal, documentPre, documentPost, documentResult;
  143. CodeEditorComponent editorOriginal, editorPre, editorPost, editorResult;
  144. Label label1, label2, label3, label4;
  145. Label instructionsLabel;
  146. TextButton generateButton { TRANS("Generate") },
  147. scanProjectButton { "Scan project for TRANS macros" },
  148. scanFolderButton { "Scan folder for TRANS macros" },
  149. loadTranslationButton { "Load existing translation file..."};
  150. std::unique_ptr<FileChooser> chooser;
  151. };