Skip to content

Commit 709e6ca

Browse files
added gd-translate command (#28)
* added gd-translate command * switched from tmpfile to subprocess lib * include cpp-subprocess dependency * rm bundled file * use cpp-subprocess * wrap output in string view * mention how to avoid the installation error * remove tail * fix * fix format * remove redundant variable * change type of spoiler to bool --------- Co-authored-by: Ren Tatsumoto <tatsu@autistici.org>
1 parent 1fd75f1 commit 709e6ca

File tree

6 files changed

+172
-3
lines changed

6 files changed

+172
-3
lines changed

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,32 @@ This script searches Anki cards in your collection that contain %GDWORD%.
188188
gd-ankisearch --field-name VocabKanji --show-fields VocabKanji,SentKanji,Image,SentAudio --word %GDWORD%
189189
```
190190

191+
## gd-translate
192+
193+
**Usage**
194+
195+
```
196+
gd-translate --sentence %GDSEARCH%
197+
gd-translate --spoiler yes --to fr --sentence %GDSEARCH%
198+
```
199+
200+
**Dependencies**
201+
202+
This script requires [Argos Translate](https://github.com/argosopentech/argos-translate) and the JA -> target language package to be installed.
203+
204+
```sh
205+
pipx install argostranslate
206+
argospm install translate-ja_en
207+
208+
argos-translate -f ja --t en "Hello World!"
209+
```
210+
211+
If you can't install `argostranslate` due to an error, try an older version of python.
212+
213+
```sh
214+
pipx install --python /usr/bin/python3.9 argostranslate
215+
```
216+
191217
## gd-mandarin
192218

193219
This script passes a sentence through mecab in order to make every part of the sentence clickable.

src/main.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "massif.h"
2424
#include "mecab_split.h"
2525
#include "precompiled.h"
26+
#include "translate.h"
2627
#include "util.h"
2728

2829
static constexpr std::string_view help_text = R"EOF(usage: {} ACTION [OPTIONS]
@@ -32,6 +33,7 @@ ACTIONS
3233
ankisearch Search word in Anki.
3334
massif Search word on Massif.
3435
images Search images on Bing.
36+
translate Translate text using argostranslate.
3537
marisa Split search string using MARISA.
3638
mecab Split search string using Mecab.
3739
strokeorder Show stroke order of a word.
@@ -92,6 +94,8 @@ auto take_action(std::span<std::string_view const> const args) -> void
9294
return massif(rest);
9395
case "gd-images"_h:
9496
return images(rest);
97+
case "gd-translate"_h:
98+
return translate(rest);
9599
case "gd-marisa"_h:
96100
return marisa_split(rest);
97101
case "gd-mecab"_h:
@@ -114,6 +118,8 @@ auto take_action(std::span<std::string_view const> const args) -> void
114118
return massif(rest);
115119
case "images"_h:
116120
return images(rest);
121+
case "translate"_h:
122+
return translate(rest);
117123
case "marisa"_h:
118124
return marisa_split(rest);
119125
case "mecab"_h:

src/precompiled.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
// Other
3131
#include <cpr/cpr.h>
32-
32+
#include <subprocess.hpp>
3333
#include <marisa/trie.h>
3434
#include <mecab.h>
3535
#include <nlohmann/json.hpp>

src/translate.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* gd-tools - a set of programs to enhance goldendict for immersion learning.
3+
* Copyright (C) 2025 Ajatt-Tools
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "precompiled.h"
20+
#include "util.h"
21+
22+
using namespace std::literals;
23+
namespace sp = subprocess;
24+
25+
static constexpr std::string_view help_text = R"EOF(usage: gd-translate [OPTIONS]
26+
27+
Translate text from Japanese to target language
28+
29+
OPTIONS
30+
--to LANG target language (default: en)
31+
--sentence SENTENCE japanese sentence to translate
32+
--spoiler yes/no black out the sentence with a spoiler box (default: no)
33+
34+
EXAMPLES
35+
gd-translate --spoiler yes --sentence %GDSEARCH%
36+
gd-translate --spoiler yes --to fr --sentence %GDSEARCH%
37+
)EOF";
38+
static constexpr std::string_view css_style = R"EOF(<style>
39+
.spoiler {
40+
background-color: black;
41+
padding: 6px;
42+
width: fit-content;
43+
}
44+
.spoiler:hover {
45+
background-color: white;
46+
}
47+
</style>)EOF";
48+
49+
struct translate_params
50+
{
51+
std::string to{ "en" };
52+
std::string gd_word;
53+
bool spoiler{ false };
54+
55+
void assign(std::string_view const key, std::string_view const value)
56+
{
57+
if (key == "--to") {
58+
to = value;
59+
} else if (key == "--sentence") {
60+
gd_word = value;
61+
} else if (key == "--spoiler" and value == "yes") {
62+
spoiler = true;
63+
}
64+
}
65+
};
66+
67+
void exec_translate(translate_params const& params)
68+
{
69+
auto cmd_argos = sp::Popen(
70+
{
71+
"argos-translate",
72+
"-f",
73+
"ja",
74+
"-t",
75+
params.to,
76+
params.gd_word,
77+
},
78+
sp::output{ sp::PIPE },
79+
sp::error{ sp::PIPE }
80+
);
81+
82+
auto const [stdout, stderr] = cmd_argos.communicate();
83+
84+
std::println("<div{}>", params.spoiler ? " class=\"spoiler\"" : "");
85+
std::println("{}", std::string_view(stdout.buf.data(), stdout.length));
86+
std::println("</div>");
87+
std::println("{}", css_style);
88+
}
89+
90+
void translate(std::span<std::string_view const> const args)
91+
{
92+
try {
93+
exec_translate(fill_args<translate_params>(args));
94+
} catch (gd::help_requested const& ex) {
95+
std::print(help_text);
96+
} catch (gd::runtime_error const& ex) {
97+
std::println("{}", ex.what());
98+
} catch (std::runtime_error const& ex) {
99+
std::println("subprocess error. {}", ex.what());
100+
}
101+
}

src/translate.h

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#pragma once
2+
3+
#include "precompiled.h"
4+
5+
void translate(std::span<std::string_view const> const args);

xmake.lua

+33-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_rules("mode.debug", "mode.release")
1414
add_rules("plugin.compile_commands.autoupdate", {outputdir = "build"})
1515

1616
add_requires("cpr >= 1.11", {configs = {ssl = true}})
17+
add_requires("cpp-subprocess")
1718
add_requires("nlohmann_json", "marisa", "rdricpp", "mecab")
1819

1920
if is_mode("debug") then
@@ -61,7 +62,7 @@ end
6162
-- Main target
6263
target(main_bin_name)
6364
set_kind("binary")
64-
add_packages("cpr","nlohmann_json", "marisa", "rdricpp", "mecab")
65+
add_packages("cpr","nlohmann_json", "marisa", "rdricpp", "mecab", "cpp-subprocess")
6566
add_files("src/*.cpp")
6667
add_cxflags("-D_GLIBCXX_ASSERTIONS")
6768
set_pcxxheader("src/precompiled.h")
@@ -130,7 +131,7 @@ if has_config("tests") then
130131
-- Tests target
131132
target("tests")
132133
set_kind("binary")
133-
add_packages("cpr", "nlohmann_json", "marisa", "catch2", "rdricpp", "mecab")
134+
add_packages("cpr", "nlohmann_json", "marisa", "catch2", "rdricpp", "mecab", "cpp-subprocess")
134135
add_files("src/*.cpp", "tests/*.cpp")
135136
remove_files("src/main.cpp")
136137
set_pcxxheader("src/precompiled.h")
@@ -160,3 +161,33 @@ package("rdricpp")
160161
import("package.tools.xmake").install(package)
161162
end)
162163
package_end()
164+
165+
package("cpp-subprocess")
166+
set_kind("library", {headeronly = true})
167+
set_homepage("https://github.com/arun11299/cpp-subprocess")
168+
set_description("Subprocessing with modern C++.")
169+
set_license("MIT")
170+
171+
set_urls("https://github.com/arun11299/cpp-subprocess.git")
172+
add_versions("2024.01.25", "4025693decacaceb9420efedbf4967a04cb028e7")
173+
174+
add_links("cpp-subprocess")
175+
176+
on_install(function (package)
177+
os.cp("subprocess.hpp", package:installdir("include"))
178+
end)
179+
180+
on_test(function (package)
181+
assert(package:check_cxxsnippets({test = [[
182+
#include <subprocess.hpp>
183+
#include <cstring>
184+
#include <thread>
185+
namespace sp = subprocess;
186+
int main() {
187+
auto obuf = sp::check_output({"ls", "-l"});
188+
std::cout << "Data : " << obuf.buf.data() << std::endl;
189+
std::cout << "Data len: " << obuf.length << std::endl;
190+
}
191+
]]}, {configs = {languages = "c++23"}}))
192+
end)
193+
package_end()

0 commit comments

Comments
 (0)