├── .gitignore
├── LICENSE
├── README.md
├── bin
├── fanyi
└── fy
├── composer.json
├── index.php
└── lib
├── console.php
├── functions.php
├── print.php
└── source.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | vendor
3 | composer.lock
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) 2019 jaggle
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Fanyi
4 |
5 | A PHP version of [afc163/fanyi](https://github.com/afc163/fanyi)
6 |
7 | > A 🇨🇳 and 🇺🇸 translate tool in your command line.
8 |
9 | 
10 |
11 |
12 |
13 | ## Install
14 |
15 | ```bash
16 | $ composer global require jjsty1e/fanyi
17 | ```
18 |
19 | > I suggest you to use [cgr](https://github.com/consolidation/cgr) to install this command to avoide dependices conflicts.
20 |
21 | then add `$HOME/.composer/vendor/bin` to `PATH` if you haven't yet.
22 |
23 | ## Usage
24 |
25 | ```bash
26 | $ fanyi word
27 | ```
28 |
29 | For short:
30 |
31 | ```bash
32 | $ fy word
33 | ```
34 |
35 | Translation data is fetched from [iciba.com](http://iciba.com) and [fanyi.youdao.com](http://fanyi.youdao.com), and only support translation between Chinese and English.
36 |
37 | In Mac/Linux bash, words will be pronounced by `say` command.
38 |
39 | Translate one word.
40 |
41 | ```bash
42 | $ fanyi love
43 | ```
44 |
45 | ```bash
46 | love 英[ lʌv ] 美[ lʌv ] ~ iciba.com
47 |
48 | - vt.& vi. 爱,热爱;爱戴;喜欢;赞美,称赞;
49 | - vt. 喜爱;喜好;喜欢;爱慕;
50 | - n. 爱情,爱意;疼爱;热爱;爱人,所爱之物;
51 |
52 | 1. Love is the radical of lovely , loveliness , and loving.
53 | Love是lovely, loveliness 及loving的词根.
54 | 2. She rhymes " love " with " dove ".
55 | 她将 " love " 与 " dove " 两字押韵.
56 | 3. In sports, love means nil.
57 | 体育中, love的意思是零.
58 | 4. It's been years since any hazardous - waste site as dramatic as Love Canal has been discovered.
59 | 自Love运河中发现触目惊心的危险废料堆放场所以来,已过去多年.
60 | 5. Is love, love, love oaths , evanescent love, absolutely love, love always can not escape this rule.
61 | 是爱,示爱, 誓爱, 逝爱, 绝爱, 爱情始终逃不过这个规律.
62 |
63 | --------
64 |
65 | love 英[ lʌv ] 美[ lʌv ] ~ fanyi.youdao.com
66 |
67 | - n. 爱;爱情;喜好;(昵称)亲爱的;爱你的;心爱的人;钟爱之物;零分
68 | - v. 爱恋(某人);关爱;喜欢(某物或某事);忠于
69 | - n. (Love) (英、菲、瑞、美)洛夫(人名)
70 |
71 | 1. love
72 | 爱, 爱情, 爱心
73 | 2. Endless Love
74 | 无尽的爱, 蓝色生死恋, 不了情
75 | 3. puppy love
76 | 早恋, 青春期恋爱, 初恋
77 |
78 | --------
79 | ```
80 |
81 | More words.
82 |
83 | ```bash
84 | $ fanyi make love
85 | ```
86 |
87 | Support Chinese, even sentence.
88 |
89 | ```bash
90 | $ fanyi 和谐
91 | ```
92 |
93 | ```bash
94 | $ fanyi 那只敏捷的棕毛狐狸跃过那只懒狗
95 | ```
96 |
--------------------------------------------------------------------------------
/bin/fanyi:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | =5.6.0",
8 | "guzzlehttp/guzzle": "^6.4",
9 | "symfony/console": "^3.4",
10 | "symfony/process": "^3.4"
11 | },
12 | "license": "MIT",
13 | "authors": [
14 | {
15 | "name": "Jaggle",
16 | "email": "singviy@gmail.com"
17 | }
18 | ],
19 | "bin": ["bin/fanyi", "bin/fy"]
20 | }
21 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | addArgument(new InputArgument('word', InputArgument::OPTIONAL, 'the word to translate'));
39 | $inputDef->addOption(new InputOption('help', 'h', InputOption::VALUE_OPTIONAL, 'show this message.', false));
40 | $inputDef->addOption(new InputOption('version', 'v', InputOption::VALUE_OPTIONAL, 'show version number', false));
41 |
42 | $input = new ArgvInput([$app, $word], $inputDef);
43 | $word = $input->getArgument('word');
44 |
45 | if (strlen($word) === 0) {
46 | if ($input->getOption('version') !== false) {
47 | return $print->output->writeln(FANYI_VERSION);
48 | }
49 |
50 | // same as $input->getOption('help') !== false
51 | $print->output->writeln('');
52 | $print->output->writeln('Examples:');
53 | $print->output->writeln(' $ fanyi word');
54 | $print->output->writeln(' $ fanyi world peace');
55 | $print->output->writeln(' $ fanyi 你好');
56 | return $print->output->writeln('');
57 | }
58 |
59 | try {
60 | $process = new Process('say ' . urldecode($word));
61 | $process->start();
62 | }
63 | catch (\Exception $e) {}
64 |
65 | $request = new Client();
66 |
67 | $promises = [];
68 |
69 | // iciba
70 | $promises[] = $request->getAsync(str_replace('${word}', $word, $source->iciba))
71 | ->then(
72 | function (ResponseInterface $response) use ($print) {
73 | if ($response->getStatusCode() === 200) {
74 | return parse_xml($response->getBody(), function ($err, $result) use ($print) {
75 | if (!$err) {
76 | return call_user_func($print->iciba, $result);
77 | }
78 | });
79 | }
80 | }, $print->error
81 | );
82 |
83 | // youdao
84 | $promises[] = $request->getAsync(str_replace('${word}', $word, $source->youdao))
85 | ->then(
86 | function (ResponseInterface $response) use ($print) {
87 | if ($response->getStatusCode() === 200) {
88 | if (($result = json_decode($response->getBody()))) {
89 | return call_user_func($print->youdao, $result);
90 | }
91 | }
92 | }, $print->error
93 | );
94 |
95 | // dictionaryapi
96 | $promises[] = $request->getAsync(str_replace('${word}', $word, $source->dictionaryapi), ['timeout' => 12])
97 | ->then(
98 | function (ResponseInterface $response) use ($print) {
99 | if ($response->getStatusCode() === 200) {
100 | return parse_xml($response->getBody(), function ($err, $result) use ($print) {
101 | if ($err) {
102 | return null;
103 | }
104 |
105 | return call_user_func($print->dictionaryapi, $result);
106 | });
107 | }
108 | }, $print->error
109 | );
110 |
111 | Promise\settle($promises)->wait();
112 | $process->wait();
113 |
--------------------------------------------------------------------------------
/lib/console.php:
--------------------------------------------------------------------------------
1 | getFormatter()->setStyle('magenta', new OutputFormatterStyle('magenta', 'default'));
14 | $output->getFormatter()->setStyle('error', new OutputFormatterStyle('red', 'default'));
15 | $output->getFormatter()->setStyle('question', new OutputFormatterStyle('cyan', 'default'));
16 | $output->getFormatter()->setStyle('gray', new OutputFormatterStyle('cyan', 'default'));
17 | $output->getFormatter()->setStyle('cyan', new OutputFormatterStyle('cyan', 'default'));
18 | $output->getFormatter()->setStyle('bold', new OutputFormatterStyle('default', 'default', ['bold']));
19 |
20 | return $output;
21 |
--------------------------------------------------------------------------------
/lib/functions.php:
--------------------------------------------------------------------------------
1 | $output,
6 | 'error' => function ($message) use ($output) {
7 | $output->writeln("{$message}");
8 | }
9 | ];
10 |
11 | $export->iciba = function ($data, $options = null) use ($output) {
12 | $output->writeln('');
13 | $ukPs = $usPs = $ps = '';
14 |
15 | if (!empty($data->ps)) {
16 | if (is_array($data->ps)) {
17 | if (!empty($data->ps[0])) $ukPs = "英[ {$data->ps[0]} ] ";
18 | if (!empty($data->ps[1])) $usPs = "美[ {$data->ps[1]} ] ";
19 | } else {
20 | $usPs = "美[ {$data->ps} ] ";
21 | }
22 | }
23 |
24 | if ($ukPs || $usPs) {
25 | $ps = ' ' . "{$ukPs}{$usPs}";
26 | }
27 | $output->write(' ' . $data->key . '');
28 | $output->writeln($ps . ' ~ iciba.com');
29 | $output->writeln('');
30 |
31 | if (!empty($data->pos)) {
32 | $trans = [];
33 | if (is_array($data->pos)) {
34 | foreach ($data->pos as $key => $item) {
35 | $trans[$key][0] = trim($item);
36 | }
37 |
38 | foreach ($data->acceptation as $key => $item) {
39 | $trans[$key][1] = trim($item);
40 | }
41 | }
42 | if (is_string($data->pos)) {
43 | $trans[] = [$data->pos, (string)$data->acceptation];
44 | }
45 | if (!empty($trans)) {
46 | foreach ($trans as $item) {
47 | $item = array_map('trim', $item);
48 | $output->writeln(" - {$item[0]} {$item[1]}");
49 | }
50 | $output->writeln('');
51 | }
52 | }
53 |
54 | if (!empty($data->sent)) {
55 | foreach ($data->sent as $key => $item) {
56 | $key++;
57 | $orig = trim(str_replace($data->key, "{$data->key}", $item->orig));
58 | $orig = trim(str_replace(ucfirst($data->key), "" . ucfirst($data->key) . "", $orig));
59 | $trans = trim($item->trans);
60 | $output->writeln(" {$key}. {$orig}");
61 | $output->writeln(str_pad(' ', 4) . "{$trans}");
62 | }
63 | }
64 |
65 | $output->writeln('');
66 | $output->writeln(' --------');
67 | };
68 |
69 | $export->youdao = function ($data, $options = null) use ($output) {
70 | $output->writeln('');
71 | $cnPtic = $hkPtic = $usPtic = $ptic = '';
72 | if (!empty($data->basic->{'uk-phonetic'})) $hkPtic = "英[ {$data->basic->{'uk-phonetic'}} ] ";
73 | if (!empty($data->basic->{'us-phonetic'})) $usPtic = "美[ {$data->basic->{'us-phonetic'}} ] ";
74 | if (empty($data->basic->{'uk-phonetic'}) &&
75 | empty($data->basic->{'us-phonetic'}) &&
76 | !empty($data->basic->phonetic)
77 | ) {
78 | $cnPtic = "[ {$data->basic->phonetic} ] ";
79 | }
80 | if ($hkPtic || $usPtic) {
81 | $ptic = ' ' . "$cnPtic{$hkPtic}{$usPtic}";
82 | }
83 | $output->write(' ' . $data->query . '');
84 | $output->writeln($ptic . ' ~ fanyi.youdao.com');
85 | $output->writeln('');
86 |
87 | if (!empty($data->basic->explains)) {
88 | foreach ($data->basic->explains as $item) {
89 | $output->writeln(" - {$item}");
90 | }
91 | $output->writeln('');
92 | }
93 |
94 | if (!empty($data->web)) {
95 | foreach ($data->web as $index => $item) {
96 | $index++;
97 | $key = trim(str_replace($data->query, "{$data->query}", $item->key));
98 | $key = trim(str_replace(ucfirst($data->query), "" . ucfirst($data->query) . "", $key));
99 | $value = implode(', ', $item->value);
100 | $output->writeln(" {$index}. {$key}");
101 | $output->writeln(str_pad(' ', 4) . "{$value}");
102 | }
103 | }
104 |
105 | if (!empty($data->translation)) {
106 | $data->translation = (array)$data->translation;
107 | foreach ($data->translation as $trans) {
108 | $output->writeln(" - {$trans}");
109 | }
110 | }
111 |
112 | $output->writeln('');
113 | $output->writeln(' --------');
114 | };
115 |
116 | $export->dictionaryapi = function ($data, $options = null) use ($output) {
117 | $output->writeln('');
118 | if (empty($data->entry)) return null;
119 | if (!is_array($data->entry)) {
120 | $data->entry = [$data->entry];
121 | }
122 | $word = $data->entry[0]->hw;
123 | $output->writeln(' ' . $word . ' ~ dictionaryapi.com');
124 | $output->writeln('');
125 | $allStrings = [];
126 | foreach ($data->entry as $key => $item) {
127 | if (!isset($item->def) || !isset($item->def->dt)) continue;
128 | $strings = $item->def->dt;
129 | if (is_string($strings)) {
130 | $strings = [$strings];
131 | }
132 | $strings = array_filter($strings, function ($val) {
133 | return is_string($val) && strlen(trim($val, ' :')) > 0;
134 | });
135 | $strings = array_map(function ($val) {
136 | return trim($val, ' :');
137 | }, $strings);
138 | $allStrings = array_merge($allStrings, $strings);
139 | }
140 |
141 | foreach ($allStrings as $key => $string) {
142 | if ($key <= 9) {
143 | $string = trim(str_replace($word, "{$word}", $string));
144 | $string = trim(str_replace(ucfirst($word), "" . ucfirst($word) . "", $string));
145 | $output->writeln(" - {$string}");
146 | }
147 | }
148 |
149 | $output->writeln('');
150 | $output->writeln(' --------');
151 | };
152 |
153 | return $export;
154 |
--------------------------------------------------------------------------------
/lib/source.json:
--------------------------------------------------------------------------------
1 | {
2 | "iciba": "http://dict-co.iciba.com/api/dictionary.php?key=D191EBD014295E913574E1EAF8E06666&w=${word}",
3 | "youdao": "http://fanyi.youdao.com/openapi.do?keyfrom=node-fanyi&key=110811608&type=data&doctype=json&version=1.1&q=${word}",
4 | "dictionaryapi": "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/${word}?key=82c5d495-ccf0-4e72-9051-5089e85c2975"
5 | }
6 |
--------------------------------------------------------------------------------