freemt commited on
Commit
7dce6dc
1 Parent(s): e57e727

Update single file separation and alignment

Browse files
data/empty.txt CHANGED
@@ -0,0 +1 @@
 
1
+
data/shakespeare-zh-en-1000.txt ADDED
@@ -0,0 +1,1000 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 总目录
2
+ 暴风雨莎士比亚全集·英汉双语本
3
+ 维洛那二绅士莎士比亚全集·英汉双语本
4
+ 快乐的温莎巧妇莎士比亚全集·英汉双语本
5
+ 一报还一报莎士比亚全集·英汉双语本
6
+ 错误的喜剧莎士比亚全集·英汉双语本
7
+ 无事生非莎士比亚全集·英汉双语本
8
+ 爱的徒劳莎士比亚全集·英汉双语本
9
+ 仲夏夜之梦莎士比亚全集·英汉双语本
10
+ 威尼斯商人莎士比亚全集·英汉双语本
11
+ 皆大欢喜莎士比亚全集·英汉双语本
12
+ 驯悍记莎士比亚全集·英汉双语本
13
+ 终成眷属莎士比亚全集·英汉双语本
14
+ 第十二夜莎士比亚全集·英汉双语本
15
+ 冬天的故事莎士比亚全集·英汉双语本
16
+ 特洛伊罗斯与克瑞西达莎士比亚全集·英汉双语本
17
+ 科利奥兰纳斯莎士比亚全集·英汉双语本
18
+ 泰特斯·安德洛尼克斯莎士比亚全集·英汉双语本
19
+ 罗密欧与朱丽叶莎士比亚全集·英汉双语本
20
+ 雅典的泰门莎士比亚全集·英汉双语本
21
+ 尤力乌斯·凯撒莎士比亚全集·英汉双语本
22
+ 麦克白莎士比亚全集·英汉双语本
23
+ 哈姆莱特莎士比亚全集·英汉双语本
24
+ 李尔王莎士比亚全集·英汉双语本
25
+ 奥瑟罗莎士比亚全集·英汉双语本
26
+ 安东尼与克莉奥佩特拉莎士比亚全集·英汉双语本
27
+ 辛白林莎士比亚全集·英汉双语本
28
+ 约翰王莎士比亚全集·英汉双语本
29
+ 理查二世莎士比亚全集·英汉双语本
30
+ 亨利四世上莎士比亚全集·英汉双语本
31
+ 亨利四世下莎士比亚全集·英汉双语本
32
+ 亨利五世莎士比亚全集·英汉双语本
33
+ 亨利六世上莎士比亚全集·英汉双语本
34
+ 亨利六世中莎士比亚全集·英汉双语本
35
+ 亨利六世下莎士比亚全集·英汉双语本
36
+ 理查三世莎士比亚全集·英汉双语本
37
+ 亨利八世莎士比亚全集·英汉双语本
38
+ 泰尔亲王佩力克里斯莎士比亚全集·英汉双语本
39
+ 两贵亲莎士比亚全集·英汉双语本
40
+ 莎士比亚诗集莎士比亚全集·英汉双语本
41
+ Copyright © Foreign Language Teaching and Research Press 2016
42
+ All rights reserved. No part of this publication may be reproduced or distributed by any means, or stored in a database or retrieval system, without the prior written permission of Foreign Language Teaching and Research Press.
43
+ 本书版权由外语教学与研究出版社独家所有。如未获得该社书面同意书中任何部分之文字及图片不得用任何方式抄袭、节录、翻印或存储利用于任何数据库及检索系统等。
44
+ Published by Foreign Language Teaching and Research Press
45
+ No. 19 Xisanhuan Beilu
46
+ Beijing, China 100089
47
+ http://www.fltrp.com
48
+ 京权图字01-2015-5979
49
+ The Tempest
50
+ Copyright©The Royal Shakespeare Company, 2007
51
+ All rights reserved
52
+ Published by arrangement with Random House, an imprint of the Random House Publishing Group, a division of Random House, Inc.
53
+ 图书在版编目CIP数据
54
+ 暴风雨英汉对照英莎士比亚Shakespeare, W.著彭镜禧译—北京外语教学与研究出版社2016.3
55
+ 莎士比亚全集·英汉双语本辜正坤等主编
56
+ 书名原文The Tempest
57
+ ISBN 978-7-5135-7223-1
58
+ I①暴… II①莎… ②彭… III①英语汉语对照读物 ②多幕剧剧本英国中世纪 IV① H319.4I
59
+ 中国版本图书馆CIP数据核字2016第055784号
60
+ 出版人  蔡剑峰
61
+ 项目负责 姚 虹 李 云
62
+ 责任编辑 文雪琴
63
+ 封面设计 奇文云海 设计顾问
64
+ 出版发行 外语教学与研究出版社
65
+ 社  址 北京市西三环北路19号100089
66
+ 网  址 http://www.fltrp.com
67
+ 版  次 2016年4月第1版
68
+ 书  号 ISBN 978-7-5135-7223-1
69
+ 凡侵权、盗版书籍线索请联系我社法律事务部
70
+ 举报电话01088817519
71
+ 电子邮箱banquan@fltrp.com
72
+ 法律顾问立方律师事务所 刘旭东律师
73
+      中咨律师事务所 殷 斌律师
74
+ 目 录
75
+ 出版说明
76
+ 莎士比亚诗体重译集序
77
+ 《暴风雨》导言
78
+ 暴风雨
79
+ 宁静中的暴风雨——译后记
80
+ Introduction to The Tempest
81
+ The Tempest
82
+ User's Guide
83
+ 返回总目录
84
+ ·1623年历史上第一部《莎士比亚全集》——著名的第一对开本First Folio由莎士比亚的演员同僚们结集出版。
85
+ ·2007年英国皇家莎士比亚剧团Royal Shakespeare Company邀约当今世界顶级莎学专家乔纳森·贝特Jonathan Bate和埃里克·拉斯姆森Eric Rasmussen对第一对开本进行了三百多年来的首次全面修订推出了新版《莎士比亚全集》。
86
+ ·2015年外语教学与研究出版社以上述新版《莎士比亚全集》为蓝本特邀当今华语翻译界和莎学界知名学者将流传下来的莎士比亚全部作品进行全新重译遂有此集。
87
+ 出版说明
88
+ 1623年莎士比亚的演员同僚们倾注心血结集出版了历史上第一部《莎士比亚全集》——著名的第一对开本这是三百多年来许多导演和演员最为钟爱的莎士比亚文本。2007年由英国皇家莎士比亚剧团Royal Shakespeare Company推出的《莎士比亚全集》则是对第一对���本首次全面的修订。
89
+ 本套《莎士比亚全集》新汉译本正是依据当今莎学界最负声望的皇家版《莎士比亚全集》翻译而成。为了让读者在阅读译本的时候也能够了解到原版的辑注风格与成果也为了方便对照查阅出版者在版式呈现上尽量遵照原版译本的凡例说明如下
90
+ 一、文体剧文有诗体和散体之分。在英文行文中诗行的标志是未及最右行末即转行且每行的首字母大写。文字连排直至最右行末转行的则为散体。中文译文对此均遵照原版处理。
91
+ 二、舞台提示
92
+ 1角色的上场与下场。在对开本中角色的上场、下场标示比较完备原版编辑者亦尽量忠实地予以了保留。在缺漏或需作订正的地方以方括号进行标注如[and Attendants]。中文译文在处理上对应英文保留了同样的标注如[及众侍从]。
93
+ 2其他舞台提示。表示其他舞台活动、改变说活对象、旁白等的舞台提示在对开本中很少出现大多为当代编辑者所添加。皇家版编辑者试图将这类指导性的directorial提示与对开本式的Folio-style提示区分开来前者置于每页最右侧采用了另一种字体当然对这种提示类型的判断存在主观的因素。有时亦有不确定的情形出现于是编辑者给予了允许选择的提示如Aside旁白表示某行剧文既可作为旁白亦可当作对话又如某个舞台活动置于箭头↓↓之间表示它可发生在一场戏中的多个不同时刻。中文译文亦遵照原版处理。
94
+ 愿广大读者在品味译者的佳文时亦体验到辑注的精审想必会有一番意想不到的新收获。
95
+ 莎士比亚诗体重译集序
96
+ 辜正坤
97
+ 他非一代骚人实属万古千秋。
98
+ 这是英国大作家本·琼森Ben Jonson在第一部《莎士比亚全集》Mr. William Shakespeares Comedies, Histories, & Tragedies, 1623扉页上题诗中的诗行。三百多年来莎士比亚在全球逐步成为一个家喻户晓的名字似乎与这句预言在在呼应。但这并非偶然言中有许多因素可以解释莎士比亚这一巨大的文化现象产生的必然性。最关键的至少有下面几点。
99
+ 首先其作品内容具有惊人的多样性。世界上很难有第二个作家像莎士比亚这样能够驾驭如此广阔的题材。他的作品内容几乎无所不包称得上英国社会的百科全书。帝王将相、走卒凡夫、才子佳人、恶棍屠夫……一切社会阶层都展现于他的笔底。从海上到陆地从宫廷到民间从国际到国内从灵界到凡尘……笔锋所指无处不至。悲剧、喜剧、历史剧、传奇剧叙事诗、抒情诗……都成为他显示天才的文学样式。从哲理的韵味到浪漫的爱情从盘根错节的叙述到一唱三叹的诗思波涛汹涌的情怀妙夺天工的笔触凡开卷展读者无不为之拊掌称绝。即使只从莎士比亚使用过的海量英语词汇来看也令人产生仰之弥高的感觉。德国语言学家马克斯·缪勒Max Müller原以为莎士比亚使用过的词汇最多为15,000个事后证明这当然是小看了语言大师的词汇储藏量。美国教授爱德华·霍尔登Edward Holden经过一番考察后认为至少达24,000个。可是他哪里知道这依然是一种低估。有学者甚至声称用电脑检索出莎士比亚用的词汇多达43,566个当然这些数据还不是莎士比亚作品之所以产生空前影响的关键因素。
100
+ 其次但也许是更重要的原因他的作品具有极高的娱乐性。文学作品的生命力在于它能寓教于乐。莎士比亚的作品不是枯燥的说教而是能够给予读者或观众极大艺术享受的娱乐性创造物往往具有明显的煽情效果有意刺激人的欲望。这种艺术取向当然不是纯粹为了娱乐而娱乐掩藏在背后的是当时西方人强有力的人本主义精神即用以人为本的价值观来对抗欧洲上千年来以神为本的宗教价值观。重欲望、重娱乐的人本主义倾向明显对重神灵、重禁欲的神本主义产生了极大的挑战。当然莎士比亚的人本主义与中国古人所主张的人本主义有很大的区别。要而言之前者在相当大的程度上肯定了人的本能欲望或原始欲望的正当性而后者则主要强调以人的仁爱为本规范人类社会秩序的高尚的道德要求。二者都具有娱乐效果但前者具有纵欲性或开放性娱乐效果后者则具有节欲性或适度自律性娱乐效果。换句话说对于16、17世纪的西方人来说莎士比亚的作品暗中契合了试图挣脱过分禁欲的宗教教义的约束而走向个性解放的千百万西方人的娱乐追求因此它会取得巨大成功是势所必然的。
101
+ 第三时势造英雄。人类其实从来不缺善于煽情的作手或视野宏阔的巨匠缺的常常是时势和机遇。莎士比亚的时代恰恰是英国文艺复兴思潮达到鼎盛的时代。禁欲千年之久的欧洲社会如堤坝围裹的宏湖表面上浪静风平其底层却汹涌着决堤的纵欲性暗流。一旦湖堤洞开飞涛大浪呼卷而下浩浩汤汤汇作长河而莎士比亚恰好是河面上乘势而起的弄潮儿其迎合西方人情趣的精湛表演遂赢得两岸雷鸣般的喝彩声。时势不光涵盖社会发展的总趋势也牵连着别的因素。比如说文学或文化理论界、政治意识形态对莎士比亚作品理解、阐释的多样性与莎士比亚作品本身内容的多样性产生相辅相成的效果。“说不尽的莎士比亚”成了西方学术界的口头禅。西方的每一种意识形态理论尤其是文学理论要想获得有效性都势必会将阐释莎士比亚的作品作为试金石。17世纪初的人文主义18世纪的启蒙主义19世纪的浪漫主义20世纪的现实主义或批判现实主义都不同程度地、选择性地把莎士比亚作品作为阐释其理论特点的例证。也许17世纪的古典主义曾经阻遏过西方人对莎士比亚作品的过度热情但是19世纪的浪漫主义流派却把莎士比亚作品推崇到无以复加的崇高地位莎士比亚俨然成了西方文学的神灵。20世纪以来西方资本主义阵营和社会主义阵营可以说在意识形态的各个方面都互相对立势同水火可是在对待莎士比亚的问题上居然有着惊人的共识与默契。不用说社会主义阵营的立场与社会主义理论的创始者马克思Karl Marx、恩格斯Friedrich Engels个人的审美情趣息息相关。马克思一家都是莎士比亚的粉丝马克思称莎士比亚为“人类最伟大的天才之一人类文学奥林波斯山上的宙斯”他号召作家们要更加莎士比亚化。恩格斯甚至指出“单是《温莎的风流娘儿们》的第一幕就比全部德国文学包含着更多的生活气息。”不用说这些话多多少少有某种程度的文学性夸张但对莎士比亚的崇高地位来说却无疑产生了极大的推动作用。
102
+ 第四1623年版《莎士比亚全集》奠定莎士比亚崇拜传统。这个版本即眼前译本所依据的皇家版《莎士比亚全集》The RSC William Shakespeare: Complete Works, 2007的主要内容。该版本产生于莎士比亚去世的第七年。莎士比亚的舞台同仁赫明奇John Heminge和康德尔Henry Condell整理出版了第一部莎士比亚戏剧集。当时的大学者、大作家本·琼森为之题诗诗中写道“他非一代骚人实属万古千秋。”这个调子奠定了莎士比亚偶像崇拜的传统。而这个传统一旦形成后人就难以反抗。英国文学中的莎士比亚偶像崇拜传统已经形成了一种自我完善、自我调整、自我更新的机制。至少近两百年来莎士比亚的文学成就已被宣传成世界文学的顶峰。
103
+ 第五现在署名“莎士比亚”的作品很可能不只是莎士比亚一个人的成果而是凝聚了当时英国若干戏剧创作精英的团体努力。众多大作家的智慧浓缩在以“莎士比亚”为代号的作品集中其成就的伟大性自然就获得了解释。当然这最后一点只是莎士比亚研究界若干学者的研究性推测远非定论。有的莎士比亚著作爱好者害怕一旦证明莎士比亚不是署名为“莎士比亚”的著作的作者莎士比亚的著作便失去了价值这完全是杞人忧天。道理很简单人们即使证明了《红楼梦》的作者不是曹雪芹或《三国演义》的作者不是罗贯中也丝毫不影响这些作品的伟大价值。同理人们即使证明了《莎士比亚全集》不是莎士比亚一个人创作的也丝毫不会影响《莎士比亚全集》是世界文学中的伟大作品这个事实反倒会更有力地证明这个事实因为集体的智慧远胜于个人。
104
+ 皇家版《莎士比亚全集》译本翻译总思路
105
+ 横亘于前的这套新译本是依据当今莎学界最负声望的皇家版《莎士比亚全集》进行翻译的而皇家版又正是以本·琼森题过诗的1623年版《莎士比亚全集》为主要依据。
106
+ 这套译本是在考察了中国现有的各种译本后根据新的历史条件和新的翻译目的打造出来的。其总的翻译思路是本套译本主编会同外语教学与研究出版社的相关领导和责任编辑讨论的结果。总起来说皇家版《莎士比亚全集》译本在翻译思路上主要遵循了以下几条
107
+ 1版本依据。如上所述本版汉译本译文以英国皇家版《莎士比亚全集》为基本依据。但在翻译过程中译者亦酌情参阅了其他版本以增进对原作的理解。
108
+ 2翻译内容包括内页所含全部文字。例如作品介绍与评论、正文、注释等。
109
+ 3注释处理问题。对于注释的处理1翻译时如果正文译文已经将英文版某注释的基本含义较准确地表达出来了则该注释即可取消2如果正文译文只是部分地将英文版对应注释的基本含义表达出来则该注释可以视情况部分或全部保留3如果注释本身存疑可以在保留原注的情况下加入译者的新注。但是所加内容务必有理有据。
110
+ 4翻译风格问题。对于风格的处理1在整体风格上译文应该尽量逼肖���作整体风格包括以诗体译诗体以散体译散体2版式风格亦尽量保留例如页边行号数码亦应在译文中保留俾便读者索查原文3在具体的文字传输处理上通常应该注重汉译本身的文字魅力增强汉译本的可读性。不宜太白话不宜太文言文白用语宜尽量自然得体。句子不要太绕注意汉语自身表达的句法结构尤其是其逻辑表达方式。意义的异化性不等于文字形式本身的异化性因此要注意用汉语的归化性来传输、保留原作含义的异化性。朱生豪先生的译本语言流畅、可读性强但可惜不是诗体有违原作形式。当下译本是要在承传朱先生译本优点的基础上根据新时代的读者审美趣味取得新的进展。梁实秋先生等的译本在达意的准确性上比朱译有所进步也是我们应该吸纳的优点。但是梁译文采不足则须注意避其短。方平先生等的译本也把莎士比亚翻译往前推进了一步在进行大规模诗体翻译方面作出了宝贵的尝试但是离真正的诗体尚有距离。此外前此的所有译本对于莎士比亚原作的色情类用语都有程度不同的忽略本套皇家版译本则尽力在此方面还原莎士比亚的本真状态论述见后文。其他还有一些译本亦都应该受到我们的关注处理原则类推。每种译本都有自己独特的东西。我们希望美的译文是这套译本的突出特点。
111
+ 5借鉴他种汉译本问题。凡是我们曾经参考过的较好的译本都在适当的地方加以注明承认前辈译者的功绩。借鉴利用是完全必要的但是要正大光明避免暗中抄袭。
112
+ 6具体翻译策略问题特别关键下文将其单列进行陈述。
113
+ 莎士比亚作品翻译领域大转折真正的诗体译本
114
+ 莎士比亚首先是一个诗人。莎士比亚的作品基本上都以诗体写成。因此要想尽可能还原本真的莎士比亚就必须将莎士比亚作品翻译成为诗体而不是散文这在莎学界已经成为共识。但是紧接而来的问题是什么叫诗体或需要什么样的诗体
115
+ 按照我们的想法1所谓诗体首先是措辞上的诗味必须尽可能浓郁2节奏上的诗味包括分行等要予以高度重视3结合中国人的审美习惯剧文可以押韵也可以不押韵。但不押韵的剧文首先要满足前两个要求。
116
+ 本全集翻译原计划由笔者一个人来完成。但是莎士比亚的创作具有惊人的多样性其作品来源也明显具有莎士比亚时代若干其他作家与作品的痕迹因此完全由某一个译者翻译成一种风格也许难免偏颇难以和莎士比亚风格的多样性相呼应。所以集众人的力量来完成大业应该更加合理更加具有可操作性。
117
+ 具体说来新时代提出了什么要求简而言之就是用真正的诗体翻译莎士比亚的诗体剧文。这个任务是朱生豪先生无法完成的。朱先生说过他在翻译莎士比亚作品时“当然预备全部用散文译出否则将要了我的命”。1显然朱先生也考虑过用诗体来翻译莎士比亚著作的问题但是他的结论是第一靠单独一个人用诗体翻译《莎士比亚全集》是办不到的会因此累死第二他用散文翻译也是不得已的办法因为只有这样他才有可能在有生之年完成《莎士比亚全集》的翻译工作。
118
+ 将《莎士比亚全集》翻译成诗体比翻译成散文体要难得多。难到什么程度呢和朱生豪先生的翻译进度比较一下就知道了。朱先生翻译得最快的时候一天可以翻译一万字。2为什么会这么快朱先生才华过人这当然是一个因素但关键因素是他是用散文翻译的。用真正的诗体就不一样了。以笔者自己的体验今日照样用散文翻译莎士比亚剧本最快时也可达到每日一万字。这是因为今日的译者有比以前更完备的注释本和众多的前辈汉译本作参考至少在理解原著时要比朱先生当年省力得多所以翻译速度上最高达到一万字是不难的。但是翻译成诗体就是另外一回事了。这比自己写诗还要难得多。写诗是自己随意发挥译诗则必须按照别人的意思发挥等于是戴着镣铐跳舞。笔者自己写诗诗兴浓时一天数百行都可以写得出来但是翻译诗一天只能是几十行统计成字数往往还不到一千字最多只是朱生豪先生散文翻译速度的十分之一。梁实秋先生翻译《莎士比亚全集》用的也是散文但是也花了37年如果要翻译成真正的诗体那么至少得370年由此可见真正的诗体《莎士比亚全集》汉译本的诞生有多么艰难。此次笔者约稿的各位译者都是用诗体翻译并且都表示花费了大量的时间皇家版《莎士比亚全集》译本凝聚了诸位译者的多少努力也就不言而喻了。
119
+ 翻译诗体分辨不是分了行就是真正的诗
120
+ 主张将莎士比亚剧作翻译成诗体成了共识但是什么才是诗体却缺乏共识。在白话诗盛行的时代许多人只是简单地认定分了行的文字就是诗这��概念。分行只是一个初级的现代诗要求甚至不必是必然要求因为有些称为诗的文字甚至连分行形式都没有。不过在莎士比亚作品的翻译上要让译文具有诗体的特征首先是必定要分行的因为莎士比亚原作本身就有严格的分行形式。这个不用多说。但是译文按莎士比亚的方式分了行只是达到了一个初级的低标准。莎士比亚的剧文读起来像不像诗还大有讲究。
121
+ 卞之琳先生对此是颇有体会的。他的译本是分行式诗体但是他自己也并不认为他译出的莎士比亚剧本就是真正的诗体译本。他说读者阅读他的译本时“如果……不感到是诗体不妨就当散文读就用散文标准来衡量”。3这是一个诚实的译者说出的诚实话。不过卞先生很谦虚他有许多剧文其实读起来还是称得上诗体的。原因是什么原因是他注意到了笔者上文提到的两点第一诗的措辞第二诗的节奏。只不过他迫于某些客观原因并没有自始至终侧重这方面的追求而已。
122
+ 显然一些译本翻译了莎士比亚的剧文在行数上靠近莎士比亚原作措辞也还流畅。这些是不是就是理想的诗体莎士比亚译本呢笔者认为这还不够。什么是诗对于中国人来说有几千年的历史我们不能脱离这个悠久的传统来讨论这个问题。为此我们不得不重新提到一些基本概念什么是诗什么是诗歌翻译
123
+ 诗歌是语言艺术诗歌翻译也就必须是语言艺术
124
+ 讨论诗歌翻译必须从讨论诗歌开始。
125
+ 诗主情。诗言志。诚然。但诗歌首先应该是一种精妙的语言艺术。同理诗歌的翻译也就不得不首先表现为同类精妙的语言艺术。若译者的语言平庸而无光彩与原作的语言艺术程度差距太远那就最多只是原诗含义的注释性文字算不得真正的诗歌翻译。
126
+ 那么何谓诗歌的语言艺术
127
+ 无他修辞造句、音韵格律一整套规矩而已。无规矩不成方圆无限制难成大师。奥运会上所有的技能比赛无不按照特定的规矩来显示参赛者高妙的技能。德国诗人歌德Johann Wolfgang von Goethe《自然和艺术》“Natur und Kunst”一诗最末两行亦彰扬此理
128
+ 非限制难见作手
129
+ 唯规矩予人自由。4
130
+ 艺术家的“自由”得心应手之谓也。诗歌既为语言艺术自然就有一整套相应的语言艺术规则。诗人应用这套规则时一旦达到得心应手的程度那就是达到了真正成熟的境界。当然规矩并非一点都不可打破但只有能够将规矩使用到随心所欲而不逾矩的程度的人才真正有资格去创立新规矩丰富旧规矩。创新是在承传旧规则长处的基础上来进行的而不是完全推翻旧规则肆意妄为。事实证明在语言艺术上凡无视积淀千年的诗歌语言规则随心所欲地巧立名目、乱行胡来者永不可能在诗歌语言艺术上取得大的成就所以歌德认为
131
+ 若徒有放任习性
132
+ 则永难至境遨游。5
133
+ 诗歌语言艺术如此需要规则如此不可放任不羁诗歌的翻译自然也同样需要相类似的要求。这个要求就是笔者前面提出的主张若原诗是精妙的语言艺术则理论上说来译诗也应是同类精妙的语言艺术。
134
+ 但是“同类”绝非“同样”。因为由于原作和译作使用的语言载体不一样其各自产生的语言艺术规则和效果也就各有各的特点大多不可同样复制、照搬。所以译作的最高目标是尽可能在译入语的语言艺术领域达到程度大致相近的语言艺术效果。这种大致相近的艺术效果程度可叫作“最佳近似度”。它实际上也就是一种翻译标准只不过针对不同的文类最佳近似度究竟在哪些因素方面可最佳程度地并不一定是最大程度地取得近似效果不是一成不变的而是具有高度的灵活性。不同的文类甚至针对不同的受众我们都可以设定不同的最佳近似度。这点在拙著《中西诗比较鉴赏与翻译理论》清华大学出版社2010年的相关章节中有详细的厘定此不赘。
135
+ 话与诗的关系话不是诗
136
+ 古人的口语本来就是白话与现在的人说的口语是白话一个道理。
137
+ 正因为白话太俗不够文雅古人慢慢将白话进行改进使它更加规范、更加准确并且用语更加丰富多彩于是文言产生。在文言的基础上还有更文的文字现象那就是诗歌于是诗歌产生。所以就诗歌而言文言味实际上就是一种特殊的诗味。文言有浅近的文言也有佶屈聱牙的文言。中国传统诗歌绝大多数是浅近的文言但绝非口语、白话。诗中有话的因素自不待言但话的因素往往正是诗试图抑制的成分。
138
+ 文言和诗歌的产生是低俗的口语进化到高雅、准确层次的标志。文言和诗歌的进一步发展使得语言的艺术性愈益增强。最终文言和诗歌完成了艺术性语言的结晶化定型。这标志着古代文学和文学语言的伟大进步。《诗经》、楚辞、唐诗、宋词���元明戏曲以及从先秦、汉、唐、宋、元至明清的散文等都是中国语言艺术逐步登峰造极的明证。
139
+ 人们往往忘记话不是诗诗是话的升华。话据说至少有几十万年的历史而诗却只有几千年的历史。白话通过漫长的岁月才升华成了诗。因此从理论上说白话诗不是最好的诗而只是低层次的、初级的诗。当一行文字写得不像是话时它也许更像诗。“太阳落下山去了”是话硬说它是诗也只是平庸的诗人人可为。而同样含义的“白日依山尽”不像是话却是真正的诗非一般人可为只有诗人才写得出。它的语言表达方式与一般人的通用白话脱离开来了实现了与通用语的偏离deviation from the norm。这里的通用语指人们天天使用的白话。试想把唐诗宋词译成白话还有多少诗味剩下来
140
+ 谢谢古代先辈们一代又一代、不屈不挠的努力话终于进化成了诗。
141
+ 但是20世纪初一些激进的中国学者鼓荡起一场声势浩大的白话文运动。
142
+ 客观说来用白话文来书写、阅读自然科学和人文科学文献例如哲学、政治学、伦理学、经济学等等文献这都是伟大的进步。这个进步甚至可以上溯到八百多年前朱熹等大学者用白话体文章传输理学思想。对此笔者非常拥护非常赞成。
143
+ 但是约一百年前的白话诗运动却未免走向了极端事实上是一种语言艺术方面的倒退行为。已经高度进化的诗词曲形式被强行要求返祖回归到三千多年前的类似白话的状态已经高度语言艺术化了的诗被强行要求退化成话。艺术性相对较低的白话反倒成了正统艺术性较高的诗反倒成了异端。其实容许口语类白话诗和文言类诗并存这才是正确的选择。但一些激进学者故意拔高白话地位在诗歌创作领域搞成白话至上主义这就走上了极端主义道路。
144
+ 这个运动影响到诗歌翻译的结果是什么呢结果是西方所有的大诗人不论是古代的还是近代的如荷马Homer、但丁Dante、莎士比亚、歌德、雨果Victor Hugo、普希金Alexander Pushkin……都莫名其妙地似乎用同一支笔写出了20世纪初才出现的味道几乎相同的白话文汉诗
145
+ 将产生这种极端性结果的原因再回推我们会清楚地明白当年的某些学者把文学艺术简单雷同于人文社会科学误解了文学艺术尤其是诗歌艺术的特殊性质误以为诗就是话混淆了诗与话的形式因素。
146
+ 针对莎士比亚戏剧诗的翻译对策
147
+ 由上可知莎士比亚的剧文既然大多是格律诗无论有韵无韵它们都是诗都有格律性。因此在汉译中我们就有必要显示出它具有格律性而这种格律性就是诗性。
148
+ 问题在于格律性是附着在语言形式上的语言改变了附着其上的格律性也就大多会消失。换句话说格律大多不可复制或模仿这就正如用钢琴弹不出二胡的效果用古筝奏不出黑管的效果一样。但是原作的内在旋律是可以模仿的只是音色变了。原作的诗性是可以换个形式营造的这就是利用汉语本身的语言特点营造出大略类似的语言艺术审美效果。
149
+ 由于换了另外一种语言媒介原作的语音美设计大多已经不能照搬、复制甚至模拟了那么我们就只好断然舍弃掉原作的许多语音美设计而代之以译入语自身的语言艺术结构产生的语音美艺术设计。当然原作的某些语音美设计还是可以尝试模拟保留的但在通常的情况下大多数的语音美已经不可能传输或复制了。
150
+ 利用汉语本身的语音审美特点来营造莎士比亚诗歌的汉译语音审美效果是莎士比亚作品翻译的一个有效途径。机械照搬原作的语音审美模式多半会失败并且在大多数的场合下也没有必要。
151
+ 具体说来这就涉及翻译莎士比亚戏剧作品时该如何处理1节奏2韵律3措辞。笔者主张在这三个方面我们都可以适当借鉴利用中国古代词曲体的某些因素。戏剧剧文中的诗行一般都不宜多用单调的律诗和绝句体式。元明戏剧为什么没有采用前此盛行的五言或七言诗行而采用了长短错杂、众体皆备的词曲体这是一种艺术形式发展的必然。元明曲体由于要更好更灵活地满足抒情、叙事、论理等诸多需要故借用发展了词的形式但不是纯粹的词而是融入了民间语汇。词这种形式涵盖了一言、二言、三言、四言、五言、六言、七言、八言……乃至十多言的长短句式因此利于表达变化莫测的情、事、理。从这个意义上看莎士比亚剧文语言单位的参差不齐状态与中文词曲体句式的参差不齐状态正好有某种相互呼应的效果。
152
+ 也许有人说莎士比亚的剧文虽然是格律诗但并不怎么押韵因此汉诗翻译也就不必押韵。这个说法也有一定道理但是道理并不充实。
153
+ 首先我们应该明白既然莎士比亚的剧文是诗体人们读到现今的散体译文或不���韵的分行译文却难以感受到其应有的诗歌风味原因即在于其音乐性太弱。如果人们能够照搬莎士比亚素体诗所惯常用的音步效果及由此引起的措辞特点当然更好。但事实上原作的节奏效果是印欧语系语言本身的效果换了一种语言其效果就大多不能搬用了所以我们只好利用汉语本身的优势来创造新的音乐美。这种音乐美很难说是原作的音乐美但是它毕竟能够满足一点即诗体剧文应该具有诗歌应有的音乐美这个起码要求。而汉译的押韵可以强化这种音乐美。
154
+ 其次莎士比亚的剧文不押韵是由诸多因素造成的。第一属于印欧语系语言的英语在押韵方面存在先天的多音节不规则形式缺陷导致押韵词汇范围相对较窄。所以对于英国诗人来说很苦于押韵难工莎士比亚的许多押韵体诗例如十四行诗在押韵方面都不很工整。其次莎士比亚的剧文虽不押韵却在节奏方面十分考究这就弥补了音韵方面的不足。第三莎士比亚的剧文几乎绝大多数是诗行对于剧作者来说每部长达两三千行的诗行行都要押韵这是一个极大的挑战很难完成。而一旦改用素体剧作者便会轻松得多。但是以上几点对于汉语译本则不是一个问题。汉语的词汇及语音构成方式决定了它天生就是一种有利于押韵的艺术性语言。汉语存在大量同韵字押韵是一件很容易的事情。汉语的语音音调变化也比莎士比亚使用的英语的音调变化空间大一倍以上。汉语音调至少有四种加上轻重变化可达六至八种而英语的音调主要局限于轻重语调两种所以存在于印欧语系文字诗歌中的频频押韵有时会产生的单调感在汉语中会在很大程度上由于语调的多变而得到缓解。故汉语戏剧剧文在押韵方面有很大的潜在优势空间实际上元明戏剧剧文频频押韵就是证明。
155
+ 第三莎士比亚的剧文虽然很多不押韵但却具极强的节奏感。他惯用的格律多半是抑扬格五音步iambic pentameter诗行。如果我们在节奏方面难以传达原作的音美或者可以通过韵律的音美来弥补节奏美的丧失这种翻译对策谓之堤内损失堤外补亦谓失之东隅收之桑榆。我们的语言在某方面有缺陷可以通过另一方面的优点来弥补。当然笔者主张在一定程度上借鉴利用传统词曲的风味却并不主张使用宋词、元曲式的严谨格律而只是追求一种过分散文化和过分格律化之间的妥协状态。有韵但是不严格要适当注意平仄但不过多追求平仄效果及诗行的整齐与否不必有太固定的建行形式只是根据诗歌本身的内容和情绪赋予适当的节奏与韵式。在措辞上则保持与白话有一段距离但是绝非佶屈聱牙的文言而是趋近典雅、但普通读者也能读懂的语言。
156
+ 最后根据翻译标准多元互补论原理由于莎士比亚作品在内容、形式及审美效应方面具有多样性因此只用一种类乎纯诗体译法来翻译所有的莎士比亚剧文也是不完美的因为单一的做法也许无形中堵塞了其他有益的审美趣味通道。因此这套译本的译风虽然整体上强调诗化、诗味但是在营造诗味的途径和程度上不是单一的。我们允许诗体译风的灵活性和创新性。多译者译法实际上也是在探索诗体译法的诸多可能性这为我们将来进一步改进这套译本铺垫了一条较宽的道路。因此译文从严格押韵、半押韵到不押韵的各个程度译本都有涉猎。但是无论是否押韵其节奏和措辞应该总是富于诗意这个要求则是统一的。这是我们对皇家版《莎士比亚全集》译本的语言和风格要求。不能说我们能完全达到这个目标但我们是往这个方向努力的。正是这样的努力使这套译本与前此译本有很大的差异在一定的意义上来说标志着中国莎士比亚著作翻译的一次大转折。
157
+ 翻译突破还原莎士比亚作品禁忌区域
158
+ 另有一个课题是中国学者从前讨论得比较少的禁忌领域即莎士比亚著作中的性描写现象。
159
+ 许多西方学者认为莎士比亚酷爱色情字眼他的著作渗透着性描写、性暗示。只要有机会他就总会在字里行间用上与性相联系的双关语。西方人很早就搜罗莎士比亚著作的此类用语编纂了莎士比亚淫秽用语词典。这类词典还不止一种。1995年我又看到弗朗基·鲁宾斯坦Frankie Rubinstein等编纂了《莎士比亚性双关语释义词典》A Dictionary of Shakespeare's Sexual Puns and Their Significance厚达372页。
160
+ 赤裸裸的性描写或过多的淫秽用语在传统中国文学作品中是受到非议的尽管有《金瓶梅》这样被判为淫秽作品的文学现象但是中国传统的主流舆论还是抑制这类作品的。莎士比亚的作品固然不是通常意义上的淫秽作品但是它的大量实际用语确实有很强的色情味。这个极鲜明的特点恰恰���前此的所有汉译本故意掩盖或在无意中抹杀掉。莎士比亚的所有汉译者尤其是像朱生豪先生这样的译者显然不愿意中国读者看到莎士比亚的文笔有非常泼辣的大量使用性相关脏话的特点。这个特点多半都被巧妙地漏译或改译。于是出现一种怪现象莎士比亚著作中有些大段的篇章变成汉语后尽管读起来是通顺的读者对这些话语却往往感到莫名其妙。以《罗密欧与朱丽叶》第一幕第一场前面的30行台词为例这是凯普莱特家两个仆人山普孙与葛莱古里之间的淫秽对话。但是读者阅读过去的汉译本时很难看到他们是在说淫秽的脏话甚至会认为这些对话只是仆人之间的胡话没有什么意义。
161
+ 不过前此的译本对这类用语和描写的态度也并不完全一样而是依据年代距离在逐步改变。朱生豪先生的译本对这些东西删除改动得最多梁实秋先生已经有所保留但还是有节制。方平先生等的译本保留得更多一些但仍然持有相当的保留态度。此外从英语的不同版本看有的版本注释得明白有的版本故意模糊有的版本注释者自己也没有弄懂这些双关语那就更别说中国译者了。
162
+ 在这一点上我们目前使用的皇家版《莎士比亚全集》是做得最好的。
163
+ 那么我们该怎样来翻译莎士比亚的这种用语呢是迫于传统中国道德取向的习惯巧妙地回避还是尽可能忠实地传达莎士比亚的本真用意我们认为前此的译本依据各自所处时代的中国人道德价值的接受状态采用了相应的翻译对策出现了某种程度的曲译这是可以理解的是特定历史条件下的产物。但是历史在前进中国人的道德观已经有了很大的改变尤其是在性禁忌领域。说实话无论我们怎样真实地还原莎士比亚著作中的性双关描写比起当代文学作品中有时无所忌讳的淫秽描写来莎士比亚还真是有小巫见大巫的感觉。换句话说目前中国人在这方面的外来道德价值接受状态已经完全可以接受莎士比亚著作中的性双关用语了。因此我们的做法是尽可能真实还原莎士比亚性相关用语的现象。在通常的情况下如果直译不能实现这种现象的传输我们就采用注释。可以说在这方面目前这个版本是所有莎士比亚汉译本中做得最超前的。
164
+ 译法示例
165
+ 莎士比亚作品的文字具有多种风格早期的、中期的和晚期的语言风格有明显区别悲剧、喜剧、历史剧、十四行诗的语言风格也有区别。甚至同样是悲剧或喜剧莎士比亚的语言风格往往也会很不相同。比如同样是属于悲剧《罗密欧与朱丽叶》剧文中就常常有押韵的段落而大悲剧《李尔王》却很少押韵同样是喜剧《威尼斯商人》是格律素体诗而《温莎的风流娘儿们》却大多是散文体。
166
+ 与此现象相应我们的翻译当然也就有多种风格。虽然不完全一一对应但我们有意避免将莎士比亚著作翻译成千篇一律的一种文体。从这个意义上说皇家版《莎士比亚全集》汉译本在某些方面采用了全新的译法。这种全新译法不是孤立的一种译法而是力求展示多种翻译风格、多种审美尝试。多样化为我们将来精益求精提供了相对更多的选择。如果现在固定为一种单一的风格那么将来要想有新的突破就困难了。概括说来我们的多种翻译风格主要包括1有韵体诗词曲风味译法2有韵体现代文白融合译法3无韵体白话诗译法。下面依次选出若干相应风格的译例供读者和有关方面品鉴。
167
+ 一、有韵体诗词曲风味译法
168
+ 有韵体诗词曲风味译法注意使用一些传统诗词曲中诗味比较浓郁的词汇同时注意遣词不偏僻节奏比较明快音韵也比较和谐。但是它们并不是严格意义上的传统诗词曲只是带点诗词曲的风味而已。例如
169
+ 女巫甲 何时我等再相逢
170
+ 闪电雷鸣急雨中
171
+ 女巫乙 待到硝烟烽火静
172
+ 沙场成败见雌雄。
173
+ 女巫丙 残阳犹挂在西空。《麦克白》第一幕第一场
174
+ 小丑甲 当时年少爱风流
175
+ 有滋有味有甜头
176
+ 行乐哪管韶华逝
177
+ 天下柔情最销愁。《哈姆莱特》第五幕第一场
178
+ 朱丽叶 天未曙罗郎何苦别意匆忙
179
+ 鸟音啼声声亮惊骇罗郎心房。
180
+ 休听作破晓云雀歌只是夜莺唱
181
+ 石榴树间夜夜有它设歌场。
182
+ 信我罗郎端的只是夜莺轻唱。
183
+ 罗密欧 不是云雀报晓不是莺歌
184
+ 看东方无情朝阳暗洒霞光
185
+ 流云万朵镶嵌银带飘如浪。
186
+ 星斗如烛恰似残灯剩微芒
187
+ 欢乐白昼悄然驻步雾嶂群岗。
188
+ 奈何我去也则生留也必亡。
189
+ 朱丽叶 听我言天际微芒非破晓霞光
190
+ 只是金乌吐射流星当空亮
191
+ 似明炬今夜为郎朗照边邦
192
+ 何愁它曼托瓦路漫远悠长。
193
+ 且稍待正无须行色皇皇仓仓。
194
+ 罗密欧 纵身陷人手蒙斧钺加诛于刑场
195
+ 只要这勾留遂你愿我欣然承当。
196
+ 让我说那天际灰朦���黎明醒眼
197
+ 乃月神眉宇幽幽映现淡淡辉光
198
+ 那歌鸣亦非云雀之讴哪怕它
199
+ 嚣然振动于头上空冥嘹亮高亢。
200
+ 我巴不得栖身此地永不他往。
201
+ 来吧死亡倘朱丽叶愿遂此望。
202
+ 如何心肝畅谈吧趁夜色迷茫。《罗密欧与朱丽叶》第三幕第五场
203
+ 二、有韵体现代文白融合译法
204
+ 有韵体现代文白融合译法的特点是基本押韵措辞上白话与文言尽量能够水乳交融充分利用诗歌的现代节奏感俾便能够念起来朗朗上口。例如
205
+ 哈姆莱特 死还是生这才是问题根本
206
+ 莫道是苦海无涯但操戈奋进
207
+ 终赢得一片清平或默对逆运
208
+ 忍受它箭石交攻敢问
209
+ 两番选择何为上乘
210
+ 死灭睡也倘借得长眠
211
+ 可治心伤愈千万肉身苦痛痕
212
+ 则岂非美境人所追寻死睡也
213
+ 睡中或有梦魇生唉症结在此
214
+ 倘能撒手这碌碌凡尘长入死梦
215
+ 又谁知梦境何形念及此忧
216
+ 不由人踌躇难定这满腹疑情
217
+ 竟使人苟延年命忍对苦难平生。
218
+ 假如借短刀一柄即可解脱身心
219
+ 谁甘愿受人世的鞭挞与讥评
220
+ 强权者的威压傲慢者的骄横
221
+ 失恋的痛楚法律的耽延
222
+ 官吏的暴虐甚或默受小人
223
+ 对贤德者肆意拳脚加身
224
+ 谁又愿肩负这如许重担
225
+ 流汗、呻吟疲于奔命
226
+ 倘非对死后的处境心存疑云
227
+ 惧那未经发现的国土从古至今
228
+ 无孤旅归来意志的迷惘
229
+ 使我辈宁愿忍受现世的忧闷
230
+ 而不敢飞身投向未知的苦境
231
+ 前瞻后顾使我们全成懦夫
232
+ 于是本色天然的决断决行
233
+ 罩上了一层思想的惨淡余阴
234
+ 只可惜诸多待举的宏图大业
235
+ 竟因此如逝水忽然转向而行
236
+ 失掉行动的名分。《哈姆莱特》第三幕第一场
237
+ 麦克白 若做了便是了则快了便是好。
238
+ 若暗下毒手却能横超果报
239
+ 割人首级却赢得绝世功高
240
+ 则一击得手便大功告成
241
+ 千了百了那么此际此宵
242
+ 身处时间之海的沙滩、岸畔
243
+ 何管它来世风险逍遥。但这种事
244
+ 现世永远有裁判的公道
245
+ 教人杀戮之策者必受杀戮之报
246
+ 给别人下毒者自有公平正义之手
247
+ 让下毒者自食盘中毒肴。《麦克白》第一幕第七场
248
+ 损神耗精愧煞了浪子风流
249
+ 都只为纵欲眠花卧柳
250
+ 阴谋好杀赌假咒坏事做到头
251
+ 心毒手狠野蛮粗暴背信弃义不知羞。
252
+ 才尝得云雨乐转眼意趣休。
253
+ 舍命追求一到手没来由
254
+ 便厌腻个透。呀恰恰像是钓钩
255
+ 但吞香饵管教你六神无主不自由。
256
+ 求时疯狂得时也疯狂
257
+ 曾有现有还想有要玩总玩不够。
258
+ 适才是甜头转瞬成苦头。
259
+ 求欢同枕前梦破云雨后。
260
+ 唉普天下谁不知这般儿歹症候
261
+ 却避不得便往这通阴曹的天堂路儿上走十四行诗第一百二十九首
262
+ 三、无韵体白话诗译法
263
+ 无韵体白话诗译法的特点是虽然不押韵但是译文有很明显的和谐节奏措辞畅达有诗味明显不是普通的口语。例如
264
+ 贡妮芮 父亲我爱您非语言所能表达
265
+ 胜过自己的眼睛、天地、自由
266
+ 超乎世上的财富或珍宝犹如
267
+ 德貌双全、康强、荣誉的生命。
268
+ 子女献爱父亲见爱至多如此
269
+ 这种爱使言语贫乏谈吐空虚
270
+ 超过这一切的比拟——我爱您。《李尔王》第一幕第一场
271
+ 李尔 国王要跟康沃尔说话慈爱的父亲
272
+ 要跟他女儿说话命令、等候他们服侍。
273
+ 这话通禀他们了吗我的气血都飙起来了
274
+ 火爆火爆公爵去告诉那烈性公爵——
275
+ 不还是别急也许他是真不舒服。
276
+ 人病了常会疏忽健康时应尽的
277
+ 责任。身子受折磨
278
+ 逼着头脑跟它受苦
279
+ 人就不由自主了。我要忍耐
280
+ 不再顺着我过度的轻率任性
281
+ 把难受病人偶然的发作错认是
282
+ 健康人的行为。我的王权废掉算了
283
+ 为什么要他坐在这里这种行为
284
+ 使我相信公爵夫妇不来见我
285
+ 是伎俩。把我的仆人放出来。
286
+ 去跟公爵夫妇讲我要跟他们说话
287
+ 现在就要。叫他们出来听我说
288
+ 不然我要在他们房门前打起鼓来
289
+ 不让他们好睡。《李尔王》第二幕第二场
290
+ 奥瑟罗 诸位德高望重的大人
291
+ 我崇敬无比的主子
292
+ 我带走了这位元老的女儿
293
+ 这是真的真的我和她结了婚说到底
294
+ 这就是我最大的罪状再也没有什么罪名
295
+ 可以加到我头上了。我虽然
296
+ 说话粗鲁不会花言巧语
297
+ 但是七年来我用尽了双臂之力
298
+ 直到九个月前我一直
299
+ 都在战场上拼死拼活
300
+ 所以对于这个世界我只知道
301
+ 冲锋向前不敢退缩落后
302
+ 也不会用漂亮的字眼来掩饰
303
+ 不漂亮的行为。不过如果诸位愿意耐心听听
304
+ 我也可以把我没有化装掩盖的全部过程
305
+ 一五一十地摆到诸位面前接受批判
306
+ 我绝没有用过什么迷魂汤药、魔法妖术
307
+ 还有什么歪门邪道——反正我得到他的女儿
308
+ 全用不着这一套。《奥瑟罗》第一幕第三场
309
+ 注释
310
+ 1 见朱生豪大约在1936年夏致宋清如信“今天下午我试译了两页莎士比亚还算顺利不过恐怕终于不过是Poor Stuff而已。当然预备全部用散文译出否则将要了我的命。”《伉俪朱生豪宋清如诗文选》下卷中国青年出版社2013年第94页
311
+ 2 朱生豪“今天因为提起了精神却很兴奋晚上译了六千字今天一共译一万字。”同上第101页
312
+ 3 卞之琳《莎士比亚悲剧四种》方志出版社2007年第4页。
313
+ 4 In der Beschränkung zeigt sich erst der Meister, / Und das Gesetz nur kann uns Freiheit geben. 参见http://www.business-it.nl/files/7d413a5dca62fc735a072b16fbf050b1-27.php.
314
+ 5 Vergebens werden ungebundene Geister / Nach der Vollendung reiner Höhe streben. 参见http://www.cosmiq.de/qa/show/3454062/Vergebens-werden-ungebundne-Geister-Nach-der-Vollendung-reiner-Hoehe-streben-Was-ist-dieBedeutung-dieser-2-Verse-Ich-komm-nicht-drauf/t.
315
+ 《暴风雨》导言
316
+ 《暴风雨》几乎可以肯定是莎士比亚独立完成的最后一出戏。我们不知道他是否预期如此。这出戏也是印在第一对开本的第一个剧本。我们也不知道它得到如此尊贵的地位是因为对开本的编辑把它当作展示品——大师艺术的总和之作——还是为了更为平凡的理由他们手头有抄写员拉尔夫·克兰Ralph Crane的干净文本排版者要着手排版莎士比亚近乎百万字的浩大工程从这本起可以有个比较容易的开始。无论它的位置来自无心抑或刻意的安排自19世纪初期以来《暴风雨》成于莎士比亚写作生涯之终、又置于作品集之首的事实大大影响了后世对这出戏的反应。它已经被视为诠释莎士比亚的试金石。
317
+ 本剧内容集中于支配与统治的问题。在开场的暴风雨中正常的社会秩序大乱水手长命令廷臣因为知道咆哮的海浪根本不在乎“什么国王”。之后第一幕第二场中详细展开的背景故事揭露了不尊重公爵名号的阴谋家我们得知普洛斯彼罗失去了米兰的权力但补偿式地得以控制岛上的爱丽儿和凯列班。腓迪南和米兰达的同心结则指向米兰与那不勒斯未来的统治。还有更进一步的政治算计西巴斯辛与安东尼奥计划谋杀阿隆佐国王和忠厚大臣贡柴罗低贱出身的角色想要推翻普洛斯彼罗让酗酒的司膳官斯丹法诺当岛上的国王。普洛斯彼罗在爱丽儿和岛上其他精灵协助下演出了一幕幕精彩的戏——使谋反者动弹不得鸟身女妖与消失的盛筵众女神及农民的假面剧那对小情人对弈的情景——这些都有助于报复过去的罪愆恢复当前的秩序并预备和谐的来日。工作完毕之后爱丽儿获得释放心痛啊1而普洛斯彼罗也在精神上做好了死亡的准备。甚至凯列班都要“寻求恩典”。
318
+ 然而莎士比亚从来都不爱简单。普洛斯彼罗以戏法变出暴风雨把宫廷的达官贵人带到这座岛主要是为了强迫他那篡位的弟弟安东尼奥悔罪。可是到了两人面对面的高潮时刻对普洛斯彼罗的饶恕与要求安东尼奥却连一个字都没有回应。他完全没有以阿隆佐在前面几行的表现为榜样而仿效之。至于安东尼奥的共犯西巴斯辛竟然还胆敢说普洛斯彼罗魔法般的先见之明是仗着邪魔之力。普洛斯彼罗能力再大也无法预料或掌控人性。如果原本没有良心以后也无法创造出良心。
319
+ 塞缪尔·泰勒·柯尔律治Samuel Taylor Coleridge2把普洛斯彼罗描述为“简直就是风暴中的莎士比亚本人”。换句话说戏中主角在开场中变出暴风雨正如剧作家变出这部戏的整个世界。普洛斯彼罗的法术驾驭了自然力量好引领其他意大利角色加入他的放逐世界同样地莎士比亚的艺术先把舞台变成一艘大海中的船然后又变成“无人的荒岛”。“法术”乃是这出戏的关键词眼。凯列班是普洛斯彼罗的“他者”因为他代表自然状态。在达尔文主义盛行的19世纪他被重塑为人类与我们动物祖先之间过渡时期“缺失的那一环”。
320
+ 普洛斯彼罗的背景故事道出了从训练统治者的“人文素养”到比较危险的魔幻“法术”的变化过程。在莎士比亚时代魔法的思维普遍存在。人人从小都相信自然界之外另有一个世界就是灵魂与妖怪的世界。“自然”与“妖魔”乃是研究及操弄超自然现象的两大支派。魔法magic即是对隐秘事物的认知和制造奇迹的法术。某些人认为这是自然哲学的最高形式这个词源于magia在古波斯语里意思是“智慧”众人称之为“神秘哲学”。它假设有不同层级的力量从不具形体的“智性的”天使魂灵到天上恒星和行星的世界再到地球事物及其形体的变化。魔法师上达高阶力量的知识以人为方式将这些能力带下来制造出奇妙的效果。科尼利厄斯·阿格里帕Cornelius Agrippa3是《论神秘哲学》De occulta philosophia一书的作者主张必须有“仪式魔法”才能达到超越星球的天使智慧。这是最高也最危险的活动层次因为——诚如同克里斯托弗·马洛Christopher Marlowe4笔下的浮士德博士Dr. Faustus的发现—��太容易变出魔鬼而不是天使。比较普通的“自然魔法”需要“媒合”天地与星体和物质世界元素之间的奇幻链接同工。历久不衰的星象影响观念乃是这种思维模式的残留。对文艺复兴时代的智者例如在米兰从业的吉罗拉莫·卡尔达诺Girolamo Cardano5而言医学、自然哲学、数学、星象学以及解梦都是紧密相连的。
321
+ 然而自然魔法始终无法躲开它的妖魔阴影。有一个像阿格里帕或卡尔达诺这样博学的智者就有一千个乡下“智婆”从事民俗医疗和算命。后者在前现代时期常常被妖魔化为女巫要为歉收、牲畜疾病及其他病痛负责。普洛斯彼罗强调他自己的白色魔法有别于凯列班母亲西考拉克斯的黑色魔法不过在这出戏里两者十分相似。他之所以从米兰被放逐到岛上是因为专注于自己的秘密研究从而给予了安东尼奥篡夺大公国的可乘之机而西考拉克斯之所以从阿尔及尔放逐到岛上是因为被控施行巫术他带着他的幼女来而西考拉克斯来的时候肚里怀着据说是跟魔鬼搞出来的孩子。两者都能指挥海潮操控以爱丽儿为代表的精灵世界。普洛斯彼罗要放弃他的魔法时用来描述法力的词语是借自另一个女巫——奥维德Ovid的古代神话故事巨著《变形记》Metamorphoses里的美狄亚Medea。在某个层次上普洛斯彼罗表达了他跟西考拉克斯之间的亲缘关系他说凯列班“这个妖怪嘛我/承认是我的”。此处主语和动词在行尾分开表明承认之前稍有犹豫这是莎士比亚后期灵活运用抑扬格五音步手法的极端例子。
322
+ 莎士比亚喜爱制造对立再把他的黑与白淡化成复杂道德里的灰色区块。在米兰普洛斯彼罗对人文素养的内观研究使他失去权位并促成暴政。在岛上他企图以他所学来弥补过失利用正向的魔法带来悔罪、收复大公国并且打造一个王朝的婚姻。然而在第五幕开始时他醒悟到真正的人性不在于运用智慧统治而在于实践更为严谨的基督徒式的德行。对16世纪的人文主义者来说君王的德行教育就是为了政治目的而修养智慧、宽宏、节制、正直。对普洛斯彼罗而言最终真正重要的是仁慈。而这是师父从徒弟那里学到的正是爱丽儿教了普洛斯彼罗“情感”的道理而不是相反。
323
+ 爱丽儿代表火与空气、和谐与音乐、耿耿忠心。凯列班属土关乎纷争、醉酒和反叛。爱丽儿的表达工具是雅致的诗凯列班的则大多是粗鲁乃至猥亵的散文一如弄臣特林鸠罗和醉汉司膳官斯丹法诺。然而令人讶异的是剧中最美丽的诗句乃是凯列班听到爱丽儿的音乐时所说的。即便是用散文凯列班亦与自然环境有一种美妙的协调他知道岛上每一个角落、每一种生物。普洛斯彼罗说他是“魔鬼天生的魔鬼对他的本性/教化根本是白搭”然而就在下一句台词里凯列班上场时说“拜托脚步轻些免得这只瞎眼的鼹鼠听到脚步声”如此富有想象力的语言立即否定了普洛斯彼罗的断言。
324
+ 凯列班据称曾要性侵米兰达可见普洛斯彼罗想驯服这个“怪物仆”、教育他具有人性的意图是失败的。然而这失败是谁的责任问题会不会出在普洛斯彼罗想要灌输到凯列班记忆里的内容上而非后者的天性一开始凯列班欢迎普洛斯彼罗到岛上来主动与他分享岛上水果——正如蒙田Montaigne散文《论食人部族》“Of the Cannibals”里所写的“高贵的野蛮人”那样那篇文章是莎士比亚剧中引用的另一来源贡柴罗治理本岛的乌托邦式“黄金时代”理想便是采自蒙田作品的英译本。凯列班只不过表现出普洛斯彼罗印刻在他身上的那种低贱而已使凯列班“污秽”的可能是普洛斯彼罗说他是“秽物”的教导。
325
+ 凯列班了解书的重要性正如现代政变领导者首先要占据电视台他强调反叛普洛斯彼罗必须从夺取他的书籍开始。然而斯丹法诺另有其书。他对凯列班说“这东西能叫您说话”—他复制普洛斯彼罗通过语言取得控制的手法不过是以另一种模式。文本的灌输被美酒的熏陶取代所亲吻的书乃是酒瓶。如此一来莎士比亚的场景对位技法营造出对话精神质疑了普洛斯彼罗的书籍使用。若说斯丹法诺和特林鸠罗以酒精达成普洛斯彼罗以教导所达成的目的两者都说服凯列班服役并分享岛上的果实这岂不是显出教导有可能只是社会控制的工具而已普洛斯彼罗时常似对他以教学建立的权力结构较感兴趣胜过他教导的实质内容。很难看出逼腓迪南搬运木柴是为了教诲德行目的其实是要他臣服。
326
+ 来到一个没有欧洲人居住的岛屿谈论“殖民地”与一个“野人”相遇并用酒精交换生存技能在语言学习过程中确立谁是主、谁是奴担心奴仆会使主人的女儿受孕欲使野蛮人寻求基督教的“恩典”但又提议把他运到英格兰展示获利提到百慕大危险的气候以及一个“华丽新世界”在所有这些方面《暴风雨》都唤起了欧洲的殖民主义精神。莎士比亚与弗吉尼亚公司的成员有联系。该公司奉王室之命成立于1606年为次年在美洲建立詹姆斯敦殖民地起了重要作用。1610年秋有一封信寄达英格兰描述派往增援殖民地的舰队在加勒比海被暴风雨吹散搭载新总督的那艘船被吹到百慕大船员和乘客都在那里过冬。虽然那封信当时没有出版手稿却流传开来至少引发两本小册子讨论这些事件。学者们为莎士比亚究竟直接引用了其中多少材料而争论不休但暴风雨及岛屿的某些细节好像是从中取材。毋庸置疑的是总督及其团队看似奇迹般幸存同时他们在巴哈马群岛发现的富饶环境乃是本剧写作之时的公众流行话题。
327
+ 大英帝国、奴隶贩卖、东西海路运送香料带来的财富——这些是后来的事。莎士比亚的戏设定在地中海不在加勒比海。凯列班严格说来不能算是岛上的原住民。然而这出戏直觉地感知殖民时期占有与驱离的动能剧力万钧不可思议所以1950年奥克塔夫·曼诺尼Octave Mannoni6写的《殖民地化进程中的心理学》The Psychology of Colonisation主张说殖民过程的运作要经由一对精神官能症交互作用于殖民者是“普洛斯彼罗情结”于被殖民者是“凯列班情结”。就是为了回应曼诺尼弗朗茨·法农Frantz Fanon7写了《黑皮肤白面具》Black Skin, White Masks从而在很大程度上塑造了“后殖民”时代的知识领域。对20世纪后期许多以英文写作的加勒比海作家来说《暴风雨》这出戏尤其是凯列班这个人物成为他们发现自己文学声音的焦点。这出戏与其说是对帝国历史的反思毋宁说是对这段历史的预知——毕竟普洛斯彼罗是被流放的人不是冒险家。
328
+ 国王剧团经常奉命在白厅御前献演自然知道从1608年岁暮起十几岁的伊丽莎白公主Princess Elizabeth就住在王宫里。她是有文化素养的少女喜欢音乐和舞蹈参与宫中节庆活动1610年在一出名叫《忒堤斯》Tethys8的假面剧里担任舞者。假面剧由皇亲、廷臣、职业演员混搭演出场面壮观音乐精致在那些年日是宫廷最时兴的表演。与莎士比亚亦友亦敌的本·琼森Ben Jonson9和设计师伊尼戈·琼斯Inigo Jones10合作为自己打出当代首席假面剧作家的名号。1608年他引进“反假面剧”或称“前假面剧”让丑怪人物即所谓“怪胎”在优雅、和谐的假面剧演出之前狂舞一番。莎士比亚也采纳了当时的流行风尚在《暴风雨》的戏中加入了订婚的假面剧以及凯列班、斯丹法诺和特林鸠罗三人闻马尿、偷窃晾衣绳上的衣服、遭群狗追逐的反假面闹剧。我们甚至觉得普洛斯彼罗这个人物可能就是对本·琼森温和的诙谐模拟他的戏剧想象受制于古典式对时间与场景统一性的要求一如琼森他也演出宫廷假面剧一如琼森。或许正因为如此几年之后琼森在他的《巴托罗缪市集》Bartholomew Fair里戏仿《暴风雨》作为回敬。
329
+ 普洛斯彼罗的基督教语言在收场白中持续最久然而他最后请求宽容的对象不是上帝而是观众。到了最后一刻取代人文主义学术的不是基督教信仰而是戏剧的信念。因此这出戏可以解读为莎士比亚为自己戏剧艺术的辩护——从浪漫主义时期以来常常就是如此理解。不过反讽的是这出戏本身对书籍乃至于对剧场的功能十分怀疑。魔法书沉入大海而假面剧及其演员也溶入空气之中就像“无根的幻景”或一场梦。
330
+ 参考资料
331
+ 剧情十二年前在那不勒斯国王阿隆佐及其弟西巴斯辛协助下米兰公爵普洛斯彼罗被他的弟弟安东尼奥篡了位。普洛斯彼罗及其幼女米兰达被流放大海到达远方小岛。他在那里靠着魔法统治精灵爱丽儿和野人凯列班。他利用法力呼风唤雨使他的敌人遭遇船难来到岛上。阿隆佐寻找儿子腓迪南担心他已经淹死。西巴斯辛密谋杀害阿隆佐夺取他的王位。酗酒的司膳官斯丹法诺和弄臣特林鸠罗遇见凯列班听了他的劝说要杀害普洛斯彼罗好由他们来统治这座岛。腓迪南和米兰达相遇两人一见钟情。普洛斯彼罗要考验腓迪南命其做苦工腓迪南通过考验普洛斯彼罗为这对年轻情侣演了一出贺婚的假面剧。在普洛斯彼罗的计划接近高潮时他正面质问敌人并宽恕他们。普洛斯彼罗赐予爱丽儿自由准备离开岛屿返回米兰。
332
+ 主要角色列有台词行数百分比/台词段数/上场次数普洛斯彼罗30/115/5爱丽儿9/45/6凯列班8/50/5斯丹法诺7/60/4贡柴罗7/52/4西巴斯辛5/67/4安东尼奥6/57/4米兰达6/49/4腓迪南6/31/4阿隆佐5/40/4特林鸠罗4/39/4。
333
+ 语体风格诗体约占80散体约占20��
334
+ 创作年代1611年。1611年11月1日宫廷演出使用的部分素材于1610年秋季以前并未问世。
335
+ 取材来源主要剧情不知取自何处但暴风雨和岛屿的某些细节似乎来自威廉·斯特雷奇William Strachey所著《托马斯·盖茨爵士船难获救真实报导》A True Reportory of the Wreck and Redemption of Sir Thomas Gates, Knight写于1610年收入1625年出版的《珀切斯游记》[Purchas his Pilgrims]或许还有西尔韦斯特·乔丹Sylvester Jourdain的《百慕大发现记》A Discovery of the Bermudas, 1610年以及弗吉尼亚公司发行的小册子《弗吉尼亚殖民地资产真实报告》A True Declaration of the Estate of the Colony in Virginia1610年有几处提到维吉尔Virgil11的《埃涅阿斯纪》Aeneid与奥维德的《变形记》特别是在第五幕第一场模仿阿瑟·戈尔丁Arthur Golding1567年翻译奥维德第七卷内美狄亚的咒文贡柴罗在第二幕第一场关于“黄金时代”的说辞基于约翰·弗洛里奥John Florio1603年所译蒙田《论食人部族》一文两者十分接近。
336
+ 文本1623年的第一对开本是唯一早期印刷本。所据为国王剧团所雇专业誊录员拉尔夫·克兰的抄写本。总体说来是高质量的印刷本。
337
+ 乔纳森·贝特Jonathan Bate
338
+ 注释
339
+ 1 或因普洛斯彼罗舍不得爱丽儿。——译者附注
340
+ 2 柯尔律治1772—1834英国诗人、评论家。——译者附注
341
+ 3 阿格里帕1486—1535德国医生、神学家、神秘学家。——译者附注
342
+ 4 马洛1564—1593英国伊丽莎白时期剧作家、诗人。——译者附注
343
+ 5 卡尔达诺1501—1576意大利医生、数学家、占星术家。——译者附注
344
+ 6 曼诺尼1899—1989法国精神分析学家、作家。——译者附注
345
+ 7 法农1925—1961出生于法属加勒比海岛屿马提尼克岛精神分析学家、哲学家。——译者附注
346
+ 8 忒堤斯为古希腊神话中的女海神之名。——译者附注
347
+ 9 琼森1572—1637英国剧作家、诗人、评论家。——译者附注
348
+ 10 琼斯1573—1652英国画家、建筑师、设计师。——译者附注
349
+ 11 维吉尔前70—前19奥古斯都时代的古罗马诗人。——译者附注
350
+ 暴风雨
351
+ 普洛斯彼罗合法的米兰公爵
352
+ 米兰达普洛斯彼罗之女
353
+ 阿隆佐那不勒斯国王
354
+ 西巴斯辛阿隆佐之弟
355
+ 安东尼奥普洛斯彼罗之弟篡位的米兰公爵
356
+ 腓迪南那不勒斯国王之子
357
+ 贡柴罗忠诚的老枢密大臣
358
+ 阿德里安和弗兰西斯科两贵族
359
+ 特林鸠罗弄臣
360
+ 斯丹法诺酗酒的司膳官
361
+ 船长
362
+ 水手长
363
+ 众水手
364
+ 凯列班未驯化的畸形奴隶
365
+ 爱丽儿空气精灵
366
+ 场景无人的荒岛
367
+ 第一幕1
368
+ 第一场第一景
369
+ 海中一船
370
+ 雷电交加暴风雨声可闻。船长与水手长上
371
+ 船长 水手长
372
+ 水手长 在船长。有什么吩咐
373
+ 船长 好兄弟去跟水手们说动作要快不然咱会搁浅啦快赶快
374
+
375
+ 众水手上
376
+ 水手长 嘿哥儿们加油加油哥儿们快点快点把中桅帆收一收。听船长的哨音。——尽管刮吧刮到你喘不过气也没关系只要船掉得过头来。
377
+ 对风暴
378
+ 阿隆佐、西巴斯辛、安东尼奥、腓迪南、贡柴罗及其他人上
379
+ 阿隆佐 好水手长留意点儿。船长在哪儿拿出男子气概来。
380
+ 水手长 各位请待在下头。
381
+ 安东尼奥 船长在哪儿啊水手长
382
+ 水手长 您没听见他吗您碍着我们的事啦。待在舱里你们这是在帮助暴风雨。
383
+ 贡柴罗 别那么说好兄弟耐心点。
384
+ 水手长 先得等大海有耐心。走开这些个大吼大叫的会理你什么国王吗去舱里闭嘴别烦我们。
385
+ 贡柴罗 好兄弟可要记得你船上载的是谁。
386
+ 水手长 没一个是我爱得超过我自个儿的。您是个大臣要是您能命令这些风雨不作声现在就平静那咱们就一根绳索都不管。施展您的权威吧。要是您办不到就感谢您活了这把年纪回舱里预备随时有什么不测——万一真有的话。——加油兄弟们——
387
+ 对众水手
388
+ 别挡了我们我说。
389
+ 对众大臣
390
+ [阿隆佐、西巴斯辛、安东尼奥与腓迪南随水手长及众水手]下
391
+ 贡泽罗 这家伙让我非常安慰。我看他没有淹死的凶相他那张脸分明就该是被绞死的。2善良的命运之神哪千万要让他被绞死用他命中注定的绞绳作我们的定锚缆索吧因为我们自己的不管用了。他若不是注定该被绞死的我们的处境就悲惨啰。
392
+
393
+ 水手长上
394
+ 水手长 放低中桅快再低再低尽量把船固定住。幕内一声呼喊混蛋叫成这样他们比这天气、比咱们发号施令还大声。
395
+ 西巴斯辛、安东尼奥与贡柴罗上
396
+ 又来啦你们来干吗的想叫我们放弃、淹死你们想要沉船哪
397
+ 西巴斯辛 我咒你喉咙长脓包你这个大吼大叫、亵渎神明、没有慈悲心肠的狗
398
+ 水手长 那你们来干。
399
+ 安东尼奥 绞死你狗东西绞死你婊子养的无耻大嗓门我们才没有你那么怕被淹死呢。
400
+ 贡柴罗 我敢担保他不会淹死就算这条船���个坚果的壳儿还小而且比流个不停的3女人漏得还凶。
401
+ 水手长 顶住风顶住风两张帆都升起来再出海升起来
402
+ 众水手浑身湿透上
403
+ 众水手 完蛋了快祷告祷告完蛋了
404
+ 水手长 什么我们都得淹死
405
+ 贡柴罗 王上和王子在祷告。咱们去助祷我们情况一样。
406
+ 西巴斯辛 我没耐性了。
407
+ 安东尼奥 我们根本是被酒鬼害了命。这个大嘴巴的无赖你淹死算了还让潮水冲刷十遍
408
+ 贡柴罗 他还是会被绞死的
409
+ 尽管每一滴海水都赌誓不会
410
+ 而且张着大口要吞他。
411
+ 水手长及众水手下
412
+ 幕内喧闹声
413
+ [后台人声] 可怜我们吧——船裂了船裂了——别了我的妻儿——别了兄弟——船裂了船裂了船裂了
414
+ 安东尼奥 咱们跟王上一起沉了吧。
415
+ 西巴斯辛 咱们去向他道别。
416
+ [安东尼奥与西巴斯辛]下
417
+ 贡柴罗 这时我情愿用千顷波涛去换一亩荒地长长的灌木、棕色的荆豆什么都行。愿上天的旨意成就但我情愿死在旱地。
418
+
419
+ 第二场第二景
420
+ 本剧以下场景都在普洛斯彼罗的海岛的各处
421
+ 普洛斯彼罗4与米兰达5上
422
+ 米兰达 至爱的父亲您若是借了法术
423
+ 使这狂涛咆哮请平息它们。
424
+ 上天好像要倾倒恶臭的沥青
425
+ 亏得大海上升到苍穹的脸颊
426
+ 熄灭了天火6。看到他们受苦我
427
+ 一同受苦。美轮美奂的一艘船——
428
+ 上面想必载着高贵的人物——
429
+ 都撞成了碎片。啊那喊叫声打在
430
+ 我的心坎上。那些可怜人都完了。
431
+ 假如我是个有权能的神我会
432
+ 先把大海沉入地下不让它
433
+ 如此吞灭这艘美好的船还有
434
+ 船里的人。
435
+ 普洛斯彼罗 安心吧
436
+ 不必再害怕。告诉你怜悯的心肠
437
+ 并没有造成损伤。
438
+ 米兰达 啊可怜哪
439
+ 普洛斯彼罗 没事。
440
+ 我所做的没有不是为了你——
441
+ 为了你我亲爱的你我女儿——你
442
+ 不明白你的身份根本不知道
443
+ 我的来历也不知道我的高贵
444
+ 超过普洛斯彼罗一个破洞窟的主人
445
+ 不过尔尔的你的父亲。
446
+ 米兰达 我从来没有
447
+ 想过要知道得更详细。
448
+ 普洛斯彼罗 时候已到
449
+ 我该多告诉你一些。帮我
450
+ 脱下我这件魔法斗篷。这样
451
+ 放下魔法斗篷
452
+ 躺好了我的魔法。你擦擦眼睛放心。
453
+ 那船难的恐怖景象触动了
454
+ 你内心至情至性的哀矜
455
+ 但我在我法术之中早已预作
456
+ 安排不叫船上任何人——
457
+ 对甚至任何生物——有
458
+ 一根毛发受到损伤尽管你
459
+ 听到哀嚎看见船沉。坐下吧
460
+ 米兰达坐下
461
+ 因为现在你必须多了解一些。
462
+ 米兰达 您常常
463
+ 要跟我讲我的身份却欲言又止
464
+ 我想追问终是徒然因您
465
+ 最后总说“慢着时机未到。”
466
+ 普洛斯彼罗 现在时机已到
467
+ 就在此刻你要张开耳朵
468
+ 听话要专心。你可记得
469
+ 我们来到这洞窟之前的时候
470
+ 我想你不能因为你那时还
471
+ 不满三岁。
472
+ 米兰达 我当然能够大人。
473
+ 普洛斯彼罗 记得什么呢有别的房屋或人吗
474
+ 告诉我有什么东西的形象
475
+ 还保存在你的记忆里。
476
+ 米兰达 很久远了
477
+ 我记得的比较像是一场梦
478
+ 不能保证准确无误。我不是
479
+ 曾经有四五个女人照顾吗
480
+ 普洛斯彼罗 你有还更多呢米兰达。可是这
481
+ 怎么还会留在你心中在时间黑暗的
482
+ 过去和深渊中你还看到什么
483
+ 你既然记得来此以前的事
484
+ 或许也记得你是怎么来的。
485
+ 米兰达 那我倒记不得了。
486
+ 普洛斯彼罗 十二年了米兰达十二年了
487
+ 你父亲原是米兰公爵一个
488
+ 大权在握的亲王。
489
+ 米兰达 大人您不是我父亲
490
+ 普洛斯彼罗 你母亲是美德的典范而
491
+ 她说你是我的女儿你父亲
492
+ 是米兰公爵他唯一的继承人
493
+ 公主也同样出身高贵。
494
+ 米兰达 啊天哪
495
+ 是什么卑鄙算计害我们流落至此
496
+ 还是说该算幸运呢
497
+ 普洛斯彼罗 都是都是孩子。
498
+ 就如你说的我们被卑鄙算计抛弃
499
+ 但幸运地获救于此。
500
+ 米兰达 啊我的心会淌血
501
+ 要是想到我给您添的麻烦
502
+ 但现在都不记得了。您请说下去。
503
+ 普洛斯彼罗 我弟弟就是你叔父叫安东尼奥的——
504
+ 我请你听好了——做兄弟的竟然
505
+ 会这样背信——世界上除了你以外
506
+ 他是我的最爱还托付他
507
+ 管理我邦的政务那时候啊
508
+ 所有城邦中要数米兰第一
509
+ 而普洛斯彼罗是至尊公爵享有如此
510
+ 殊荣说到人文素养7
511
+ 无人能比。我既一心一意钻研
512
+ 便把政务交给弟弟
513
+ 对我邦大事愈发生疏因为全神
514
+ 贯注于玄秘研究。你那虚伪的叔父——
515
+ 你在听吗
516
+ 米兰达 大人专注极了。
517
+ 普洛斯彼罗 一旦学会了怎样答应请托
518
+ 怎样拒绝该升迁哪个该把哪个
519
+ 野心大的压一压重新任命
520
+ 我原来的僚属或改派职务
521
+ 或新设职位等到掌控了
522
+ 官员与官位使全邦人心
523
+ 都听他发号施令他就成了
524
+ 那爬藤掩蔽了我王者的躯干
525
+ 还吸吮我的精髓。——你没在听。
526
+ 米兰达 啊好大人我有。
527
+ 普洛斯彼罗 我请你听好了。
528
+ 我这般荒废俗��完全
529
+ 独处专注于修炼我的智能
530
+ 单单这样退隐研究就远非
531
+ 凡夫俗子所能理解我那虚伪的弟弟
532
+ 更起了祸心于是我的信任
533
+ 像纯良的父亲竟然生出
534
+ 相反的虚假而且程度大得
535
+ 如同我的信任——那真是无限量、
536
+ 无止境的信赖。他如此这般
537
+ 不仅掌管了我赋税的收入
538
+ 还有我权力所能要求的一切。就像
539
+ 惯说谎言的人相信自己的真实
540
+ 使自己的记忆成为罪人
541
+ 好遮掩他的谎言他竟然
542
+ 相信自己真的是公爵篡夺爵位
543
+ 以公爵之尊执行职务
544
+ 享有一切特权。于是他的野心增长——
545
+ 你在听吗
546
+ 米兰达 大人您的故事可以治好聋子。
547
+ 普洛斯彼罗 为了使他扮演的和他所替代的中间
548
+ 没有阻隔他势必要成为独尊的
549
+ 米兰公爵。我呢——可怜人——我的藏书室
550
+ 就是够大的公国日常公爵的庶务
551
+ 他认为我已无能处理。他去勾结——
552
+ 因为渴求权力——那不勒斯国王
553
+ 向他缴纳年贡向他效忠
554
+ 以自己的小王冠8臣服于他的王冠
555
+ 使从未俯首的我邦——唉可怜的米兰——
556
+ 卑躬屈膝可耻已极。
557
+ 米兰达 啊天哪
558
+ 普洛斯彼罗 你听他的契约和结果再告诉我
559
+ 这算不算是兄弟9。
560
+ 米兰达 我若认为祖母不贞洁
561
+ 便是犯罪了
562
+ 好母亲也会生出坏儿子。
563
+ 普洛斯彼罗 现在说那契约。
564
+ 那不勒斯国王一向是我的
565
+ 死对头就同意我弟弟的要求
566
+ 也就是他接受了俯首称臣
567
+ 以及为数不知多少的进贡
568
+ 作为回报应立即把我和家人
569
+ 从米兰根除并把大好的米兰
570
+ 和它所有的荣衔赐给我弟弟。于是
571
+ 招募了一支叛军在注定的
572
+ 某一天午夜安东尼奥打开了
573
+ 米兰的城门在死寂的黑暗中
574
+ 办事的人把我和哭啼的你
575
+ 匆忙逐出去。
576
+ 米兰达 哀哉可怜哪
577
+ 我记不得当时怎么哭的
578
+ 要再哀哭一次这种场合
579
+ 会拧出我的眼泪。
580
+ 普洛斯彼罗 再听我多讲一点
581
+ 然后我就把你带回我们
582
+ 眼前这件事没有它我这故事
583
+ 就不着边际了。
584
+ 米兰达 为什么他们不在
585
+ 当时灭了我们
586
+ 普洛斯彼罗 问得好丫头。我的故事
587
+ 会引发这问题。宝贝他们不敢
588
+ 我的百姓十分爱我也没敢在
589
+ 这件事情上打上血腥的记号倒是
590
+ 用好看的颜色涂抹他们丑陋的目的。
591
+ 简单说他们赶我们上了一条船
592
+ 带我们出海约有几里格在那里备有
593
+ 一个朽坏的木桶没有任何配备
594
+ 没有工具、船帆没有桅杆就连老鼠
595
+ 都本能地离开了。你我被丢进去
596
+ 向着朝我们咆哮的大海哭泣向着
597
+ 海风哀叹海风怜悯地回报以哀叹
598
+ 虽是有情却害了我们10。
599
+ 米兰达 哎呀我那时
600
+ 是您多大的累赘啊
601
+ 普洛斯彼罗 啊你是我的
602
+ 保命小天使。我向大海滴下
603
+ 咸咸泪水因重担而呻吟
604
+ 这时上天赐给你的刚毅
605
+ 使你绽放微笑这就激起了我
606
+ 坚忍的勇气无惧于
607
+ 未来的遭遇。
608
+ 米兰达 我们怎么上岸的
609
+ 普洛斯彼罗坐下
610
+ 普洛斯彼罗 靠着上天恩典。
611
+ 我们有一些食物还有些淡水是
612
+ 一位那不勒斯贵族贡柴罗——
613
+ 他那时受命负责这个计划——
614
+ 出于慈悲给我们的另外还
615
+ 有华服、织物、杂项、必需品
616
+ 后来都派上用场。同样出于好意
617
+ 他知道我爱书从我的图书室
618
+ 给了我一些卷册这些是我
619
+ 珍爱超过我的公国的。
620
+ 米兰达 但愿我能
621
+ 见到那个人。
622
+ 普洛斯彼罗 现在我要起来了11
623
+ 普洛斯彼罗起身
624
+ 你还是坐好听我们海上伤心事的结尾。
625
+ 我们来到这个岛在这里
626
+ 我当你的教师使你比别的公主
627
+ 更有长进她们把更多闲暇
628
+ 用于无意义的事老师也没那么关心。
629
+ 米兰达 愿上天报答您。现在我求您大人
630
+ 因为这事还在我心里搅扰您为何
631
+ 要兴起这海上风暴
632
+ 普洛斯彼罗 这就要知道
633
+ 由于极为奇妙的意外宽宏的命运之神——
634
+ 如今是我亲爱的夫人12——已经把我的仇家
635
+ 带到岸边。而我通过预知的能力
636
+ 发现我的命盘最高点要依靠
637
+ 一颗最吉祥的星星它的影响力
638
+ 我现在若不追求反而忽视我的运势
639
+ 就会永远衰败。到此别再问了
640
+ 你想睡了。这睡意很好
641
+ 就顺着它吧。我知道你别无选择。——
642
+ 米兰达入睡
643
+ 过来仆人来。我已经预备好了。
644
+ 过来好爱丽儿来吧。
645
+ 爱丽儿上
646
+ 爱丽儿 大王万福尊贵的主万福我是来
647
+ 满足您一切心愿的。无论是飞翔
648
+ 是游泳是跳入火坑是腾上
649
+ 卷云只要是您权威的吩咐
650
+ 爱丽儿无不全力以赴13。
651
+ 普洛斯彼罗 精灵你可曾
652
+ 执行我的命令完整地演出暴风雨
653
+ 爱丽儿 每一项都做了。
654
+ 我上了国王的船一会儿在船头
655
+ 一会儿在船腰、甲板在每间船舱
656
+ 我化成吓人的火焰时而我自行分身
657
+ 四处放火在中桅、桅杆间的横木、
658
+ 船首斜桅上我分别燃烧
659
+ 然后并成一团。天神乔武14的闪电
660
+ 恐怖雷鸣的先行者也不及我
661
+ 迅速眼睛都跟不上。火焰和霹雳
662
+ 如地狱般呼号似乎要围攻力大
663
+ ���比的海神使他胆大的波涛战栗
664
+ 没错他恐怖的三叉戟发抖。
665
+ 普洛斯彼罗 我的好精灵
666
+ 有谁镇静、安稳连这场骚乱都
667
+ 无法搅扰他的理智
668
+ 爱丽儿 没有哪一个
669
+ 不感到激动疯狂做出
670
+ 绝望时的怪异举动。除了水手人人
671
+ 都跳入白沫飞溅的海里逃离那艘
672
+ 随着我起火的船王子腓迪南
673
+ 头发倒竖——像芦苇不像头发——
674
+ 是头一个跳海的大喊“地狱都空了
675
+ 所有魔鬼都在这里。”
676
+ 普洛斯彼罗 啊我的好精灵
677
+ 但不是到了岸边了吗
678
+ 爱丽儿 很近了主人。
679
+ 普洛斯彼罗 可是爱丽儿他们可平安
680
+ 爱丽儿 毫发无损。
681
+ 他们浮水的衣服上没有任何污斑
682
+ 反而比先前更新。而且照你的吩咐
683
+ 我把他们一组组分散在岛上。
684
+ 国王的儿子我让他独自上岸
685
+ 留他在岛上一个僻静的角落
686
+ 叹着气吹凉了空气坐在那儿
687
+ 手臂像这样打着伤心的结。
688
+ 交叉双臂
689
+ 普洛斯彼罗 关于国王的大船、
690
+ 水手们说说你是如何处置的
691
+ 还有船队的其他人
692
+ 爱丽儿 安全停在港里
693
+ 国王的船。在那深深隐秘处有一回
694
+ 你要我到风暴不断的百慕大采露15
695
+ 半夜叫我起来去的地方船藏在那里。
696
+ 水手们全都安顿在甲板下
697
+ 我念了个咒加上他们遭受的劳累
698
+ 使他们睡着了。至于其他船只——
699
+ 被我打散的——又都聚拢
700
+ 如今在地中海上
701
+ 悲伤地驶回那不勒斯
702
+ 他们以为亲眼见到王船遇难
703
+ 国王驾崩。
704
+ 普洛斯彼罗 爱丽儿给你的任务
705
+ 完全做到了但还有别的工作。
706
+ 现在什么时候了
707
+ 爱丽儿 过了正午。
708
+ 普洛斯彼罗 至少两个沙漏钟16。从现在到六点
709
+ 这段时间我们必须珍惜使用。
710
+ 爱丽儿 还有别的苦工吗既然你要我工作
711
+ 容我提醒你你答应过我的事
712
+ 现在还没做到。
713
+ 普洛斯彼罗 怎么啦不开心
714
+ 你能有什么要求
715
+ 爱丽儿 我的自由。
716
+ 普洛斯彼罗 在时限未满之前别提了
717
+ 爱丽儿 我请你
718
+ 记得我对你服务良好
719
+ 不曾对你撒谎没做错事伺候你
720
+ 既无怨恨也无牢骚。你确实答应过
721
+ 减免我一整年劳役。
722
+ 普洛斯彼罗 你难道忘了
723
+ 我把你从多大的折磨中解救出来
724
+ 爱丽儿 没有。
725
+ 普洛斯彼罗 你忘了。以为很了不得
726
+ 能脚踩海底泥浆
727
+ 在锐利的北风中奔驰
728
+ 在霜冻的时候替我
729
+ 到地脉办事。
730
+ 爱丽儿 我没有大人。
731
+ 普洛斯彼罗 你撒谎邪恶的东西你难道忘了
732
+ 那可恶的巫婆西考拉克斯她又老又坏
733
+ 身体驼成了一圈你难道忘了她吗
734
+ 爱丽儿 没有大人。
735
+ 普洛斯彼罗 你忘了。她出生在哪里说告诉我。
736
+ 爱丽儿 大人在阿尔及尔。
737
+ 普洛斯彼罗 哦是这样啊我得要
738
+ 每个月重讲一遍你的过去——
739
+ 你都忘了。这个该死的巫婆西考拉克斯
740
+ 因为作恶多端搬弄巫术
741
+ 骇人听闻你知道的从
742
+ 阿尔及尔被赶出来。只因她做过的一件事
743
+ 他们没有要她的命。这不是真的吗
744
+ 爱丽儿 是的大人。
745
+ 普洛斯彼罗 这个蓝眼皮的巫婆怀着身孕被带来
746
+ 水手们把她留在这里。你我的奴才
747
+ 照你自己所说当时是她的仆人。
748
+ 而因为你是个太柔弱的精灵
749
+ 受不了她那粗蛮可恶的指挥
750
+ 拒绝了她的重大命令。
751
+ 她盛怒难消之下靠着
752
+ 比较有力的手下帮助把你
753
+ 关在一棵裂开的松树里
754
+ 你被囚禁在那树缝中痛苦了
755
+ 十二年。在那期间她死了
756
+ 留你在那里呻吟不已
757
+ 像水车叶片打到水面。当时这座岛——
758
+ 除了她在这里落下的崽子、
759
+ 巫婆所产长满斑点的小畜生——没有
760
+ 一个人类。
761
+ 爱丽儿 是的凯列班她的儿子。
762
+ 普洛斯彼罗 蠢货17我说。他那个凯列班
763
+ 我留下来使唤的家伙。你最清楚
764
+ 我见到你时你受的什么苦。你的呻吟
765
+ 叫狼子嚎哭穿透怒熊的
766
+ 胸膛。那种折磨是要用来
767
+ 对付下地狱者的连西考拉克斯
768
+ 也无法解除。是我的法术
769
+ 当我到来听见了你的痛呼打开了
770
+ 那松树放你出来。
771
+ 爱丽儿 谢谢你主人。
772
+ 普洛斯彼罗 你再嘟哝我就撕裂一棵栎树
773
+ 把你钉在它纠结的五脏里直到
774
+ 你哀嚎满十二个冬天。
775
+ 爱丽儿 请原谅主人。
776
+ 我会顺服命令
777
+ 乖乖做我精灵该做的。
778
+ 普洛斯彼罗 就这么办。两天之后
779
+ 我就放了你。
780
+ 爱丽儿 高贵的主人
781
+ 要我做什么请说要我做什么
782
+ 普洛斯彼罗 去把自己扮成海上仙女
783
+ 只有你我看得到别人的
784
+ 眼睛都不能见。去打扮好
785
+ 再回来这里。去认真办事去
786
+ [爱丽儿]下
787
+ 醒醒心肝醒醒。你睡得很好。醒来。
788
+ 对米兰达
789
+ 米兰达 您那故事不可思议
790
+ 使我睡意浓浓。
791
+ 普洛斯彼罗 驱散它。跟我来。
792
+ 咱们去看我那奴才凯列班他从不
793
+ 好言好语回答我们。
794
+ 米兰达 这是个恶棍大人我不要看他。
795
+ 普洛斯彼罗 但情势如此
796
+ 我们少不了他。他替我们生火、
797
+ 担木柴做些对我们有利的
798
+ 差事。喂喝奴才凯列班
799
+ 你这泥块��说话啊
800
+ 凯列班 里面还有足够木柴。
801
+ 幕内
802
+ 普洛斯彼罗 出来我说还有别的事要你做。
803
+ 来你这乌龟什么时候
804
+ 爱丽儿扮成水中仙女上
805
+ 精美的幻影曼妙的爱丽儿
806
+ 耳朵凑过来。
807
+ 爱丽儿 主人一定照办。
808
+
809
+ 普洛斯彼罗 你这恶毒的奴才魔鬼在你
810
+ 邪恶老娘肚子里搞出来的东西快出来
811
+ 凯列班上
812
+ 凯列班 愿我娘用乌鸦羽毛从毒泥潭
813
+ 抹上来的最毒的露水滴在
814
+ 你们两个身上愿西南风18吹上你们
815
+ 叫你们浑身长水疱
816
+ 普洛斯彼罗 为此今夜保管要叫你抽筋
817
+ 侧边疼痛叫你不能呼吸刺猬19
818
+ 会通宵达旦都在你身上
819
+ 做日常工作——你会被刺戳得
820
+ 密密麻麻像蜂巢一般每一刺
821
+ 都比做蜂巢的蜜蜂所螫还痛。
822
+ 凯列班 我得吃饭才行。
823
+ 这座岛原是我娘西考拉克斯传给我的
824
+ 你夺了去。你刚来的时候
825
+ 用手抚摸我疼爱我给我里头
826
+ 放了莓果20的水喝还教我怎么
827
+ 称呼白天和夜晚发亮的
828
+ 大光跟小光。那时候我爱你
829
+ 带你看遍岛上的风貌
830
+ 淡水泉、咸水坑、荒地和沃土。
831
+ 我该死竟那样做愿西考拉克斯一切
832
+ 蛊物——蛤蟆、甲虫、蝙蝠——都降到你们身上
833
+ 因为我当初是我自己的王
834
+ 如今成了你唯一的臣民
835
+ 你把我圈在这硬石窟里
836
+ 和整个岛隔离。
837
+ 普洛斯彼罗 你这漫天撒谎的奴才
838
+ 鞭子可以感动你慈善没用尽管你是
839
+ 脏东西我还是以仁慈的关切待你让你
840
+ 住在我自己的洞里直到你企图强暴
841
+ 我的孩子。
842
+ 凯列班 喔呵喔呵那件事做成了可就好啦
843
+ 你不让我做否则我早在这岛上
844
+ 生满凯列班了。
845
+ 米兰达 可憎的奴才
846
+ 什么好的都不肯学
847
+ 一切坏的无所不为。我是可怜你
848
+ 费心教你说话每个钟点都教你
849
+ 一样东西。野人你当时不懂
850
+ 自己讲什么只是叽里咕噜像那
851
+ 最粗暴的野兽我还教你言辞
852
+ 表达你的意思。然而由于你的恶性——
853
+ 尽管学习了——里面还是有善性
854
+ 无法共存之处。因此你被关在
855
+ 这石窟里罪有应得其实
856
+ 关进监狱里都算轻罚了。
857
+ 凯列班 你教我语言我得到的好处
858
+ 是知道怎样诅咒。愿红疮要你的命
859
+ 因为你教我你的语言。
860
+ 普洛斯彼罗 巫婆子孙滚
861
+ 把木柴给我们扛进来要快。你最好
862
+ 也打别的杂。你敢耸肩浑球
863
+ 假如我的吩咐你不做或是
864
+ 做得不情不愿我就罚你抽筋抽不停
865
+ 叫你一身骨头痛楚使你吼叫
866
+ 声音大得连野兽听了都要发抖。
867
+ 凯列班 不要求求你。——
868
+ 我必须服从他的法力太强
869
+ 旁白
870
+ 能够控制我娘的神赛得玻21
871
+ 去当他的奴仆。
872
+ 普洛斯彼罗 好了奴才快去
873
+ 凯列班下
874
+ 腓迪南上爱丽儿隐形上边弹边唱
875
+ 爱丽儿 快来这黄沙滩上唷
876
+
877
+ 手儿牵着手。
878
+ 屈个膝亲一亲
879
+ 浪涛就平静。
880
+ 曼妙舞步到处跳
881
+ 可爱的精灵啊你们要
882
+ 唱副歌。
883
+ [众精灵 幕内唱]副歌散乱地
884
+ 听啊听汪喔
885
+ 看门狗在叫汪喔。
886
+ 爱丽儿 听啊听我听到
887
+ 趾高气扬的雄鸡叫
888
+ 高唱咯咯啼哆哆。
889
+ 腓迪南 这音乐在哪儿在天上在地下
890
+ 这会儿停了。一定是唱给
891
+ 岛上什么神明的。我坐在岸边
892
+ 还在哀哭我父王遇难
893
+ 这音乐从水上飘过来
894
+ 甜美乐音平息了怒涛
895
+ 和我的伤痛。我一路跟着——
896
+ 也许是它引领我——可是停了。
897
+ 不又开始了。
898
+ 爱丽儿 令尊躺在五处22
899
+
900
+ 骸骨已然成珊瑚
901
+ 珍珠乃是他双目。
902
+ 全身骨肉虽朽腐
903
+ 一经大海精细雕
904
+ 成为珍贵稀世宝。
905
+ 海仙敲钟常纪念
906
+ [众精灵 幕内唱]副歌叮咚。
907
+ 爱丽儿 听啊听叮咚声连连。
908
+ 腓迪南 这小调的确在悼念淹死的家父。
909
+ 这不是凡俗事物世上也没有
910
+ 这种声音。此刻就在我头上。
911
+ 普洛斯彼罗 打开你的眼帘
912
+ 告诉我你看到那边有什么。
913
+ 米兰达 那是什么啊是个精灵吗
914
+ 天哪它在东张西望大人我真觉得
915
+ 它长得好英俊。但它是个精灵。
916
+ 普洛斯彼罗 不对丫头。它也吃也睡也有跟咱们
917
+ 一样的感觉一样的。你看的这位帅哥
918
+ 遭了船难。若不是他因为哀伤而略有
919
+ 愁容——哀伤会破坏美貌——你可以说他
920
+ 长得挺好的。他失去了伙伴
921
+ 到处找他们呢。
922
+ 米兰达 我要称他为
923
+ 仙品因为我见过的人
924
+ 从没这么高贵的。
925
+ 普洛斯彼罗 有苗头了我看
926
+ 旁白
927
+ 正中我的下怀。——精灵啊好精灵
928
+ 对爱丽儿
929
+ 因你办了这件事我两天之内就释放你。
930
+ 腓迪南 一定是了这是那些歌声
931
+ 侍候的女神请准许我的祈祷
932
+ 告诉我您是否住在这岛上
933
+ 可否给我一些好指点
934
+ 让我知道在这里该当如何。最后
935
+ 也最重要的是——啊惊为天人23的您——
936
+ 您是个少女24不是
937
+ 米兰达 没什么可惊的先生
938
+ 但确实是少女。
939
+ 腓迪南 讲我的语言天哪
940
+ 讲这语言的人里我最高贵
941
+ 如果是在讲这语言的地方。
942
+ 普洛斯彼罗 怎么说最高贵
943
+ 这要让那不勒斯国王听到你成了什么
944
+ 腓迪南 孤家寡人25像现在这样听你说起
945
+ 那不勒斯国王我很诧异。他听得见我26
946
+ 而因此我落泪。我就是那不勒斯的王
947
+ 双眼目睹我父王船难泪水
948
+ 没有停过。
949
+ 米兰达 哀哉好可怜
950
+ 腓迪南 是啊真的还有他的全部大臣米兰公爵
951
+ 和他英俊的儿子也失散了。27
952
+ 普洛斯彼罗 米兰公爵
953
+ 旁白
954
+ 和他更俊的女儿可以质疑你
955
+ 但现在不合适。他们才一见面
956
+ 就眉来眼去。——机灵的爱丽儿
957
+ 对爱丽儿
958
+ 为此我要释放你。——过来说句话少爷
959
+ 对腓迪南
960
+ 我只怕你搞错了什么28。过来说句话。
961
+ 米兰达 为什么父亲话说得这么凶这
962
+ 才是我见过的第三个男人是第一个
963
+ 使我思慕的。愿怜悯打动父亲
964
+ 跟我同样想法。
965
+ 腓迪南 啊您若是闺女
966
+ 感情也没有他属我要让你
967
+ 成为那不勒斯的王后。
968
+ 普洛斯彼罗 且慢先生还要跟你说句话呢。——
969
+ 他们俩都爱上对方了但这事进展太快
970
+ 旁白
971
+ 我得弄得困难些免得奖品赢得轻易
972
+ 变得没价值。——还有话要说。我命令你
973
+ 对腓迪南
974
+ 仔细听我说你在这里篡夺了
975
+ 不属于你的名号来到
976
+ 这岛上当奸细想要偷取
977
+ 本岛主的岛。
978
+ 腓迪南 不然。我堂堂一个男子汉。
979
+ 米兰达 不会有任何邪物存在这座神庙29
980
+ 假如邪灵有这么美好的居所
981
+ 美善事物必然会抢着进去住。
982
+ 普洛斯彼罗 跟我来。——
983
+ 对腓迪南
984
+ 你别替他讲话他是个叛贼。——过来
985
+ 对米兰达/对腓迪南
986
+ 我要锁上你的脖子和双脚
987
+ 给你喝海水你的食物是
988
+ 淡水河蚌30、枯干的根茎还有
989
+ 橡实的壳。跟过来。
990
+ 腓迪南 不
991
+ 我要反抗这种待遇除非
992
+ 我的敌人力量胜得过我。
993
+ 他拔剑但被法术所制动弹不得
994
+ 米兰达 啊亲爱的父亲
995
+ 不要给他太鲁莽的考验
996
+ 他温文有礼并不可怕31。
997
+ 普洛斯彼罗 什么哼
998
+ 你小子来教训我——把剑收起来叛贼。
999
+ 对腓迪南
1000
+ 你摆摆架势却不敢打你的良心
data/shakespeare-zh-en-2000.txt ADDED
The diff for this file is too large to render. See raw diff
data/shakespeare-zh-en-4000.txt ADDED
The diff for this file is too large to render. See raw diff
gradio_queue.db CHANGED
Binary files a/gradio_queue.db and b/gradio_queue.db differ
img/df.png ADDED
img/plt.png ADDED
img/temp.png ADDED
radiobee/__main__.py CHANGED
@@ -14,6 +14,7 @@ from itertools import zip_longest
14
  from socket import socket, AF_INET, SOCK_STREAM
15
 
16
  from sklearn.cluster import DBSCAN # noqa
 
17
  import joblib
18
  from varname import nameof
19
  import logzero
@@ -33,19 +34,10 @@ if "." not in sys.path:
33
  sys.path.insert(0, ".")
34
 
35
  import gradio as gr
36
- from radiobee.process_upload import process_upload
37
- from radiobee.files2df import files2df
38
- from radiobee.file2text import file2text
39
- from radiobee.lists2cmat import lists2cmat
40
- from radiobee.gen_pset import gen_pset
41
- from radiobee.gen_aset import gen_aset
42
- from radiobee.align_texts import align_texts
43
-
44
- from radiobee.cmat2tset import cmat2tset
45
 
46
- # from radiobee.plot_df import plot_df
47
- # from radiobee.plot_cmat import plot_cmat
48
- from radiobee.trim_df import trim_df
49
 
50
  sns.set()
51
  sns.set_style("darkgrid")
@@ -91,25 +83,6 @@ def process_2upoads(file1, file2):
91
  return df
92
 
93
 
94
- def error_msg(
95
- msg: Optional[str],
96
- title: str = "error message",
97
- ) -> Tuple[Union[pd.DataFrame, None], None, None, None, None]:
98
- """Prepare error message for fn outputs."""
99
- if msg is None:
100
- msg = "none..."
101
-
102
- try:
103
- msg = msg.__str__()
104
- except Exception as exc:
105
- msg = str(exc)
106
-
107
- df = pd.DataFrame([msg], columns=[title])
108
-
109
- # return df, *((None,) * 4) # pyright complains
110
- return df, None, None, None, None
111
-
112
-
113
  if __name__ == "__main__":
114
  debug = True
115
  # debug = False
@@ -261,6 +234,7 @@ if __name__ == "__main__":
261
  [
262
  "data/test-dual.txt",
263
  "data/empty.txt",
 
264
  "linear",
265
  "None",
266
  "None",
@@ -301,7 +275,8 @@ if __name__ == "__main__":
301
  # modi outputs
302
  outputs = [
303
  out_df,
304
- "plot",
 
305
  out_file_dl,
306
  out_file_dl_excel,
307
  out_df_aligned,
@@ -310,229 +285,6 @@ if __name__ == "__main__":
310
  # outputs = ["dataframe"]
311
  # outputs = ["dataframe", "dataframe", ]
312
 
313
- # def fn(file1, file2):
314
- # def fn(file1, file2, min_samples, eps):
315
- def fn(
316
- file1,
317
- file2,
318
- tf_type,
319
- idf_type,
320
- dl_type,
321
- norm,
322
- eps,
323
- min_samples,
324
- ):
325
- # modi fn
326
- """Process inputs and return outputs."""
327
- logger.debug(" *debug* ")
328
-
329
- # conver "None" to None for those Radio types
330
- for _ in [idf_type, dl_type, norm]:
331
- if _ in "None":
332
- _ = None
333
-
334
- # logger.info("file1: *%s*, file2: *%s*", file1, file2)
335
- if file2 is not None:
336
- logger.info("file1.name: *%s*, file2.name: *%s*", file1.name, file2.name)
337
- else:
338
- logger.info("file1.name: *%s*, file2: *%s*", file1.name, file2)
339
-
340
- # bypass if file1 or file2 is str input
341
- # if not (isinstance(file1, str) or isinstance(file2, str)):
342
- text1 = file2text(file1)
343
-
344
- if file2 is None:
345
- logger.debug("file2 is None")
346
- text2 = ""
347
-
348
- # TODO split text1 to text1 and text2
349
- else:
350
- logger.debug("file2.name: %s", file2.name)
351
- text2 = file2text(file2)
352
-
353
- if not text1 or not text2:
354
- msg = (
355
- "one of the files is empty: "
356
- f"text1[:10]: [{text1[:10]}], text2[:10]: [{text2[:10]}]"
357
- )
358
- # return (pd.DataFrame([msg], columns=['error message']), *((None,) * 4))
359
- return error_msg(msg)
360
-
361
- lang1, _ = fastlid(text1)
362
- lang2, _ = fastlid(text2)
363
-
364
- df1 = files2df(file1, file2)
365
-
366
- lst1 = [elm for elm in df1.text1 if elm]
367
- lst2 = [elm for elm in df1.text2 if elm]
368
- # len1 = len(lst1) # noqa
369
- # len2 = len(lst2) # noqa
370
-
371
- cmat = lists2cmat(
372
- lst1,
373
- lst2,
374
- tf_type=tf_type,
375
- idf_type=idf_type,
376
- dl_type=dl_type,
377
- norm=norm,
378
- )
379
-
380
- tset = pd.DataFrame(cmat2tset(cmat))
381
- tset.columns = ["x", "y", "cos"]
382
-
383
- df_trimmed = trim_df(df1)
384
- _ = """
385
- df_trimmed = pd.concat(
386
- [
387
- df1.iloc[:4, :],
388
- pd.DataFrame(
389
- [
390
- [
391
- "...",
392
- "...",
393
- ]
394
- ],
395
- columns=df1.columns,
396
- ),
397
- df1.iloc[-4:, :],
398
- ],
399
- ignore_index=1,
400
- )
401
- # """
402
-
403
- # process lst1, lst2 to obtained df_aligned
404
- # quick fix ValueError: not enough values to unpack (expected at least 1, got 0)
405
- # fixed in gen_pet, but we leave the loop here
406
- for min_s in range(min_samples):
407
- logger.info(" min_samples, using %s", min_samples - min_s)
408
- try:
409
- pset = gen_pset(
410
- cmat,
411
- eps=eps,
412
- min_samples=min_samples - min_s,
413
- delta=7,
414
- )
415
- break
416
- except ValueError:
417
- logger.info(" decrease min_samples by %s", min_s + 1)
418
- continue
419
- except Exception as e:
420
- logger.error(e)
421
- continue
422
- else:
423
- # break should happen above when min_samples = 2
424
- raise Exception("bummer, this shouldn't happen, probably another bug")
425
-
426
- min_samples = gen_pset.min_samples
427
-
428
- # will result in error message:
429
- # UserWarning: Starting a Matplotlib GUI outside of
430
- # the main thread will likely fail."
431
- _ = """
432
- plot_cmat(
433
- cmat,
434
- eps=eps,
435
- min_samples=min_samples,
436
- xlabel=lang1,
437
- ylabel=lang2,
438
- )
439
- # """
440
-
441
- # move plot_cmat's code to the main thread here
442
- # to make it work
443
- xlabel = lang1
444
- ylabel = lang2
445
-
446
- len1, len2 = cmat.shape
447
- ylim, xlim = len1, len2
448
-
449
- # does not seem to show up
450
- logger.debug(" len1 (ylim): %s, len2 (xlim): %s", len1, len2)
451
- if debug:
452
- print(f" len1 (ylim): {len1}, len2 (xlim): {len2}")
453
-
454
- df_ = pd.DataFrame(cmat2tset(cmat))
455
- df_.columns = ["x", "y", "cos"]
456
-
457
- sns.set()
458
- sns.set_style("darkgrid")
459
-
460
- # close all existing figures, necesssary for hf spaces
461
- plt.close("all")
462
-
463
- # if sys.platform not in ["win32", "linux"]:
464
- plt.switch_backend("Agg") # to cater for Mac, thanks to WhiteFox
465
-
466
- # figsize=(13, 8), (339, 212) mm on '1280x800+0+0'
467
- fig = plt.figure(figsize=(13, 8))
468
-
469
- # gs = fig.add_gridspec(2, 2, wspace=0.4, hspace=0.58)
470
- gs = fig.add_gridspec(1, 2, wspace=0.4, hspace=0.58)
471
- ax_heatmap = fig.add_subplot(gs[0, 0]) # ax2
472
- ax0 = fig.add_subplot(gs[0, 1])
473
- # ax1 = fig.add_subplot(gs[1, 0])
474
-
475
- cmap = "viridis_r"
476
- sns.heatmap(cmat, cmap=cmap, ax=ax_heatmap).invert_yaxis()
477
- ax_heatmap.set_xlabel(xlabel)
478
- ax_heatmap.set_ylabel(ylabel)
479
- ax_heatmap.set_title("cos similarity heatmap")
480
-
481
- fig.suptitle(f"alignment projection\n(eps={eps}, min_samples={min_samples})")
482
-
483
- _ = DBSCAN(min_samples=min_samples, eps=eps).fit(df_).labels_ > -1
484
- # _x = DBSCAN(min_samples=min_samples, eps=eps).fit(df_).labels_ < 0
485
- _x = ~_
486
-
487
- # max cos along columns
488
- df_.plot.scatter("x", "y", c="cos", cmap=cmap, ax=ax0)
489
-
490
- # outliers
491
- df_[_x].plot.scatter("x", "y", c="r", marker="x", alpha=0.6, ax=ax0)
492
- ax0.set_xlabel(xlabel)
493
- ax0.set_ylabel(ylabel)
494
- ax0.set_xlim(xmin=0, xmax=xlim)
495
- ax0.set_ylim(ymin=0, ymax=ylim)
496
- ax0.set_title(
497
- "max along columns ('x': outliers)\n"
498
- "potential aligned pairs (green line), "
499
- f"{round(sum(_) / xlim, 2):.0%}"
500
- )
501
-
502
- # clustered
503
- # df_[_].plot.scatter("x", "y", c="cos", cmap=cmap, ax=ax1)
504
- # ax1.set_xlabel(xlabel)
505
- # ax1.set_ylabel(ylabel)
506
- # ax1.set_xlim(0, len1)
507
- # ax1.set_title(f"potential aligned pairs ({round(sum(_) / len1, 2):.0%})")
508
- # end of plot_cmat
509
-
510
- src_len, tgt_len = cmat.shape
511
- aset = gen_aset(pset, src_len, tgt_len)
512
- final_list = align_texts(aset, lst2, lst1) # note the order
513
-
514
- # df_aligned = df_trimmed
515
- df_aligned = pd.DataFrame(final_list, columns=["text1", "text2", "likelihood"])
516
-
517
- # swap text1 text2
518
- df_aligned = df_aligned[["text2", "text1", "likelihood"]]
519
- df_aligned.columns = ["text1", "text2", "likelihood"]
520
-
521
- _ = df_aligned.to_csv(index=False)
522
- file_dl = Path(f"{Path(file1.name).stem[:-8]}-{Path(file2.name).stem[:-8]}.csv")
523
- file_dl.write_text(_, encoding="utf8")
524
-
525
- # file_dl.write_text(_, encoding="gb2312") # no go
526
-
527
- file_dl_xlsx = Path(
528
- f"{Path(file1.name).stem[:-8]}-{Path(file2.name).stem[:-8]}.xlsx"
529
- )
530
- df_aligned.to_excel(file_dl_xlsx)
531
-
532
- # return df_trimmed, plt
533
- return df_trimmed, plt, file_dl, file_dl_xlsx, df_aligned
534
- # modi outputs
535
-
536
  server_port = 7860
537
  with socket(AF_INET, SOCK_STREAM) as sock:
538
  sock.settimeout(0.01) # 10ms
@@ -546,6 +298,8 @@ if __name__ == "__main__":
546
  else:
547
  raise SystemExit(f"Tried {numb} times to no avail, giving up...")
548
 
 
 
549
  # moved to userguide.rst in docs
550
  article = dedent(
551
  """
@@ -584,6 +338,18 @@ if __name__ == "__main__":
584
 
585
  logger.info("running at port %s", server_port)
586
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  iface = gr.Interface(
588
  # fn=greet,
589
  # inputs="text",
@@ -592,11 +358,12 @@ if __name__ == "__main__":
592
  # inputs=["file", "file"],
593
  # outputs="text",
594
  # outputs="html",
595
- fn=fn,
 
596
  inputs=inputs,
597
  outputs=outputs,
598
  title="radiobee-aligner🔠",
599
- description="WIP showcasing a blazing fast dualtext aligner, currrently supported language pairs: en-zh/zh-en",
600
  article=article,
601
  examples=examples,
602
  # theme="darkgrass",
14
  from socket import socket, AF_INET, SOCK_STREAM
15
 
16
  from sklearn.cluster import DBSCAN # noqa
17
+
18
  import joblib
19
  from varname import nameof
20
  import logzero
34
  sys.path.insert(0, ".")
35
 
36
  import gradio as gr
 
 
 
 
 
 
 
 
 
37
 
38
+ # from radiobee.error_msg import error_msg
39
+ from radiobee.process_upload import process_upload
40
+ from radiobee.gradiobee import gradiobee
41
 
42
  sns.set()
43
  sns.set_style("darkgrid")
83
  return df
84
 
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  if __name__ == "__main__":
87
  debug = True
88
  # debug = False
234
  [
235
  "data/test-dual.txt",
236
  "data/empty.txt",
237
+ # None, # does not work
238
  "linear",
239
  "None",
240
  "None",
275
  # modi outputs
276
  outputs = [
277
  out_df,
278
+ # "plot",
279
+ gr.outputs.Image(label="plot"),
280
  out_file_dl,
281
  out_file_dl_excel,
282
  out_df_aligned,
285
  # outputs = ["dataframe"]
286
  # outputs = ["dataframe", "dataframe", ]
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  server_port = 7860
289
  with socket(AF_INET, SOCK_STREAM) as sock:
290
  sock.settimeout(0.01) # 10ms
298
  else:
299
  raise SystemExit(f"Tried {numb} times to no avail, giving up...")
300
 
301
+ description = "WIP showcasing a blazing fast dualtext aligner, currrently supported language pairs: en-zh/zh-en"
302
+
303
  # moved to userguide.rst in docs
304
  article = dedent(
305
  """
338
 
339
  logger.info("running at port %s", server_port)
340
 
341
+ _ = """
342
+ inputs = ...
343
+ outputs = ...
344
+ # properly
345
+ # define gradiobee to take inputs and spil out outputs
346
+
347
+ iface = gr.Interface(
348
+ fn=gradiobee,
349
+ inputs,
350
+ outputs,
351
+ )
352
+ # """
353
  iface = gr.Interface(
354
  # fn=greet,
355
  # inputs="text",
358
  # inputs=["file", "file"],
359
  # outputs="text",
360
  # outputs="html",
361
+ # fn=fn,
362
+ fn=gradiobee,
363
  inputs=inputs,
364
  outputs=outputs,
365
  title="radiobee-aligner🔠",
366
+ description=description,
367
  article=article,
368
  examples=examples,
369
  # theme="darkgrass",
radiobee/detect.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Detect language via polyglot and fastlid."""
2
+ # pylint: disable=
3
+
4
+ from typing import Any, Callable, List, Optional
5
+
6
+ from polyglot.text import Detector
7
+ import polyglot.detect.base
8
+ from polyglot.detect.base import UnknownLanguage
9
+ from fastlid import fastlid
10
+
11
+ from logzero import logger
12
+
13
+ polyglot.detect.base.logger.setLevel("ERROR")
14
+
15
+
16
+ def with_func_attrs(**attrs: Any) -> Callable:
17
+ """Define func_attrs."""
18
+
19
+ def with_attrs(fct: Callable) -> Callable:
20
+ for key, val in attrs.items():
21
+ setattr(fct, key, val)
22
+ return fct
23
+
24
+ return with_attrs
25
+
26
+
27
+ # @with_func_attrs(set_languages=None)
28
+ # def detect(text: str) -> str:
29
+ def detect(text: str, set_languages: Optional[List[str]] = None) -> str:
30
+ """Detect language via polyglot and fastlid."""
31
+ # if not text.strip(): return "en"
32
+ try:
33
+ _ = [(elm.code[:2], elm.confidence) for elm in Detector(text).languages]
34
+ detect.lang_conf = _
35
+ lang, conf = _[0]
36
+ except UnknownLanguage:
37
+ if set_languages is None:
38
+ def_lang = "en"
39
+ else:
40
+ # def_lang = set_languages[-1]
41
+ def_lang = set_languages[0]
42
+ logger.warning(" UnknownLanguage exception: probably snippet too short, setting to %s", def_lang)
43
+ lang, conf = def_lang, 0
44
+ except Exception as exc:
45
+ logger.error(exc)
46
+ lang, conf = "en", 0
47
+
48
+ del conf
49
+
50
+ # set_languages = detect.set_languages
51
+ if set_languages is None:
52
+ return lang
53
+
54
+ # set_languages is set
55
+ if not isinstance(set_languages, (list, tuple)):
56
+ logger.warning("set_languages (%s) ought to be a list/tuple")
57
+
58
+ if lang in set_languages:
59
+ return lang
60
+
61
+ # lang not in set_languages, use fastlid
62
+ fastlid.set_languages = set_languages
63
+ lang, _ = fastlid(text)
64
+
65
+ return lang
radiobee/error_msg.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Prepare an error message for gradiobee."""
2
+ from typing import Optional, Tuple, Union
3
+ import pandas as pd
4
+
5
+
6
+ def error_msg(
7
+ msg: Optional[Union[str, Exception]],
8
+ title: str = "error message",
9
+ ) -> Tuple[Union[pd.DataFrame, None], None, None, None, None]:
10
+ """Prepare an error message for gradiobee outputs."""
11
+ if msg is None:
12
+ msg = "none..."
13
+
14
+ try:
15
+ msg = msg.__str__()
16
+ except Exception as exc:
17
+ msg = str(exc)
18
+
19
+ df = pd.DataFrame([msg], columns=[title])
20
+
21
+ # return df, *((None,) * 4) # pyright complains
22
+ return df, None, None, None, None
radiobee/gradiobee.py ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradiobee."""
2
+ from pathlib import Path
3
+ from itertools import zip_longest
4
+
5
+ # import tempfile
6
+
7
+ from logzero import logger
8
+ from sklearn.cluster import DBSCAN
9
+ from fastlid import fastlid
10
+
11
+ import numpy as np
12
+ import pandas as pd
13
+ import matplotlib
14
+ import matplotlib.pyplot as plt
15
+ import seaborn as sns
16
+
17
+ # from radiobee.process_upload import process_upload
18
+ from radiobee.files2df import files2df
19
+ from radiobee.file2text import file2text
20
+ from radiobee.lists2cmat import lists2cmat
21
+ from radiobee.gen_pset import gen_pset
22
+ from radiobee.gen_aset import gen_aset
23
+ from radiobee.align_texts import align_texts
24
+ from radiobee.cmat2tset import cmat2tset
25
+ from radiobee.trim_df import trim_df
26
+ from radiobee.error_msg import error_msg
27
+ from radiobee.text2lists import text2lists
28
+
29
+ sns.set()
30
+ sns.set_style("darkgrid")
31
+
32
+ debug = False
33
+ debug = True
34
+
35
+
36
+ def gradiobee(
37
+ file1,
38
+ file2,
39
+ tf_type,
40
+ idf_type,
41
+ dl_type,
42
+ norm,
43
+ eps,
44
+ min_samples,
45
+ # debug=False,
46
+ ):
47
+ """Process inputs and return outputs."""
48
+ logger.debug(" *debug* ")
49
+
50
+ # possible further switchse
51
+ # para_sent: para/sent
52
+ # sent_ali: default/radio/gale-church
53
+ plot_dia = True # noqa
54
+
55
+ # outputs: check return
56
+ # if outputs is modified, also need to modify error_msg's outputs
57
+
58
+ # convert "None" to None for those Radio types
59
+ for _ in [idf_type, dl_type, norm]:
60
+ if _ in "None":
61
+ _ = None
62
+
63
+ # logger.info("file1: *%s*, file2: *%s*", file1, file2)
64
+ if file2 is not None:
65
+ logger.info("file1.name: *%s*, file2.name: *%s*", file1.name, file2.name)
66
+ else:
67
+ logger.info("file1.name: *%s*, file2: *%s*", file1.name, file2)
68
+
69
+ # bypass if file1 or file2 is str input
70
+ # if not (isinstance(file1, str) or isinstance(file2, str)):
71
+ text1 = file2text(file1)
72
+
73
+ if file2 is None:
74
+ logger.debug("file2 is None")
75
+ text2 = ""
76
+
77
+ # TODO split text1 to text1 and text2
78
+ else:
79
+ logger.debug("file2.name: %s", file2.name)
80
+ text2 = file2text(file2)
81
+
82
+ # if not text1.strip() or not text2.strip():
83
+ if not text1.strip():
84
+ msg = (
85
+ "file 1 is apparently empty... Upload a none empty file and try again."
86
+ # f"text1[:10]: [{text1[:10]}], "
87
+ # f"text2[:10]: [{text2[:10]}]"
88
+ )
89
+ return error_msg(msg)
90
+
91
+ # single file
92
+ # when text2 is empty
93
+ # process file1/text1: split text1 to text1 text2 to zh-en
94
+ if not text2.strip():
95
+ _ = [elm.strip() for elm in text1.splitlines() if elm.strip()]
96
+ if not _: # essentially empty file1
97
+ return error_msg("Nothing worthy of processing in file 1")
98
+
99
+ _ = zip_longest(_, [""])
100
+ _ = pd.DataFrame(_, columns=["text1", "text2"])
101
+ df_trimmed = trim_df(_)
102
+
103
+ # text1 = loadtext("data/test-dual.txt")
104
+ list1, list2 = text2lists(text1)
105
+
106
+ lang1 = text2lists.lang1
107
+ lang2 = text2lists.lang2
108
+ offset = text2lists.offset # noqa
109
+
110
+ _ = """
111
+ ax = sns.heatmap(lists2cmat(list1, list2), cmap="gist_earth_r") # ax=plt.gca()
112
+ ax.invert_yaxis()
113
+ ax.set(
114
+ xlabel=lang1,
115
+ ylabel=lang2,
116
+ title=f"cos similary heatmap \n(offset={offset})",
117
+ )
118
+ plt_loc = "img/plt.png"
119
+ plt.savefig(plt_loc)
120
+ # """
121
+
122
+ # output_plot = plt_loc # for gr.outputs.Image
123
+
124
+ #
125
+ _ = zip_longest(list1, list2, fillvalue="")
126
+ df_aligned = pd.DataFrame(
127
+ _,
128
+ columns=["text1", "tex2"]
129
+ )
130
+
131
+ file_dl = Path(f"{Path(file1.name).stem[:-8]}-{lang1}-{lang2}.csv")
132
+ file_dl_xlsx = Path(
133
+ f"{Path(file1.name).stem[:-8]}-{lang1}-{lang2}.xlsx"
134
+ )
135
+
136
+ # return df_trimmed, output_plot, file_dl, file_dl_xlsx, df_aligned
137
+
138
+ # end if single file
139
+ else: # file1 file 2: proceed
140
+ lang1, _ = fastlid(text1)
141
+ lang2, _ = fastlid(text2)
142
+
143
+ df1 = files2df(file1, file2)
144
+
145
+ list1 = [elm for elm in df1.text1 if elm]
146
+ list2 = [elm for elm in df1.text2 if elm]
147
+ # len1 = len(list1) # noqa
148
+ # len2 = len(list2) # noqa
149
+
150
+ file_dl = Path(f"{Path(file1.name).stem[:-8]}-{Path(file2.name).stem[:-8]}.csv")
151
+ file_dl_xlsx = Path(
152
+ f"{Path(file1.name).stem[:-8]}-{Path(file2.name).stem[:-8]}.xlsx"
153
+ )
154
+
155
+ df_trimmed = trim_df(df1)
156
+ # --- end else single
157
+
158
+ try:
159
+ cmat = lists2cmat(
160
+ list1,
161
+ list2,
162
+ tf_type=tf_type,
163
+ idf_type=idf_type,
164
+ dl_type=dl_type,
165
+ norm=norm,
166
+ )
167
+ except Exception as exc:
168
+ logger.error(exc)
169
+ return error_msg(exc)
170
+
171
+ tset = pd.DataFrame(cmat2tset(cmat))
172
+ tset.columns = ["x", "y", "cos"]
173
+
174
+ _ = """
175
+ df_trimmed = pd.concat(
176
+ [
177
+ df1.iloc[:4, :],
178
+ pd.DataFrame(
179
+ [
180
+ [
181
+ "...",
182
+ "...",
183
+ ]
184
+ ],
185
+ columns=df1.columns,
186
+ ),
187
+ df1.iloc[-4:, :],
188
+ ],
189
+ ignore_index=1,
190
+ )
191
+ # """
192
+
193
+ # process list1, list2 to obtained df_aligned
194
+ # quick fix ValueError: not enough values to unpack (expected at least 1, got 0)
195
+ # fixed in gen_pet, but we leave the loop here
196
+ for min_s in range(min_samples):
197
+ logger.info(" min_samples, using %s", min_samples - min_s)
198
+ try:
199
+ pset = gen_pset(
200
+ cmat,
201
+ eps=eps,
202
+ min_samples=min_samples - min_s,
203
+ delta=7,
204
+ )
205
+ break
206
+ except ValueError:
207
+ logger.info(" decrease min_samples by %s", min_s + 1)
208
+ continue
209
+ except Exception as e:
210
+ logger.error(e)
211
+ continue
212
+ else:
213
+ # break should happen above when min_samples = 2
214
+ raise Exception("bummer, this shouldn't happen, probably another bug")
215
+
216
+ min_samples = gen_pset.min_samples
217
+
218
+ # will result in error message:
219
+ # UserWarning: Starting a Matplotlib GUI outside of
220
+ # the main thread will likely fail."
221
+ _ = """
222
+ plot_cmat(
223
+ cmat,
224
+ eps=eps,
225
+ min_samples=min_samples,
226
+ xlabel=lang1,
227
+ ylabel=lang2,
228
+ )
229
+ # """
230
+
231
+ # move plot_cmat's code to the main thread here
232
+ # to make it work
233
+ xlabel = lang1
234
+ ylabel = lang2
235
+
236
+ len1, len2 = cmat.shape
237
+ ylim, xlim = len1, len2
238
+
239
+ # does not seem to show up
240
+ logger.debug(" len1 (ylim): %s, len2 (xlim): %s", len1, len2)
241
+ if debug:
242
+ print(f" len1 (ylim): {len1}, len2 (xlim): {len2}")
243
+
244
+ df_ = pd.DataFrame(cmat2tset(cmat))
245
+ df_.columns = ["x", "y", "cos"]
246
+
247
+ sns.set()
248
+ sns.set_style("darkgrid")
249
+
250
+ # close all existing figures, necesssary for hf spaces
251
+ plt.close("all")
252
+
253
+ # if sys.platform not in ["win32", "linux"]:
254
+ # going for noninterative
255
+ # to cater for Mac, thanks to WhiteFox
256
+ plt.switch_backend("Agg")
257
+
258
+ # figsize=(13, 8), (339, 212) mm on '1280x800+0+0'
259
+ fig = plt.figure(figsize=(13, 8))
260
+
261
+ # gs = fig.add_gridspec(2, 2, wspace=0.4, hspace=0.58)
262
+ gs = fig.add_gridspec(1, 2, wspace=0.4, hspace=0.58)
263
+ ax_heatmap = fig.add_subplot(gs[0, 0]) # ax2
264
+ ax0 = fig.add_subplot(gs[0, 1])
265
+ # ax1 = fig.add_subplot(gs[1, 0])
266
+
267
+ cmap = "viridis_r"
268
+ sns.heatmap(cmat, cmap=cmap, ax=ax_heatmap).invert_yaxis()
269
+ ax_heatmap.set_xlabel(xlabel)
270
+ ax_heatmap.set_ylabel(ylabel)
271
+ ax_heatmap.set_title("cos similarity heatmap")
272
+
273
+ fig.suptitle(f"alignment projection\n(eps={eps}, min_samples={min_samples})")
274
+
275
+ _ = DBSCAN(min_samples=min_samples, eps=eps).fit(df_).labels_ > -1
276
+ # _x = DBSCAN(min_samples=min_samples, eps=eps).fit(df_).labels_ < 0
277
+ _x = ~_
278
+
279
+ # max cos along columns
280
+ df_.plot.scatter("x", "y", c="cos", cmap=cmap, ax=ax0)
281
+
282
+ # outliers
283
+ df_[_x].plot.scatter("x", "y", c="r", marker="x", alpha=0.6, ax=ax0)
284
+ ax0.set_xlabel(xlabel)
285
+ ax0.set_ylabel(ylabel)
286
+ ax0.set_xlim(xmin=0, xmax=xlim)
287
+ ax0.set_ylim(ymin=0, ymax=ylim)
288
+ ax0.set_title(
289
+ "max along columns (x: outliers)\n"
290
+ "potential aligned pairs (green line), "
291
+ f"{round(sum(_) / xlim, 2):.0%}"
292
+ )
293
+
294
+ plt_loc = "img/plt.png"
295
+ plt.savefig(plt_loc)
296
+
297
+ # clustered
298
+ # df_[_].plot.scatter("x", "y", c="cos", cmap=cmap, ax=ax1)
299
+ # ax1.set_xlabel(xlabel)
300
+ # ax1.set_ylabel(ylabel)
301
+ # ax1.set_xlim(0, len1)
302
+ # ax1.set_title(f"potential aligned pairs ({round(sum(_) / len1, 2):.0%})")
303
+ # end of plot_cmat
304
+
305
+ src_len, tgt_len = cmat.shape
306
+ aset = gen_aset(pset, src_len, tgt_len)
307
+ final_list = align_texts(aset, list2, list1) # note the order
308
+
309
+ # df_aligned
310
+ df_aligned = pd.DataFrame(final_list, columns=["text1", "text2", "likelihood"])
311
+
312
+ # swap text1 text2
313
+ df_aligned = df_aligned[["text2", "text1", "likelihood"]]
314
+ df_aligned.columns = ["text1", "text2", "likelihood"]
315
+
316
+ # ===
317
+ if plot_dia:
318
+ output_plot = "img/plt.png"
319
+ else:
320
+ output_plot = None
321
+
322
+ _ = df_aligned.to_csv(index=False)
323
+ file_dl.write_text(_, encoding="utf8")
324
+
325
+ # file_dl.write_text(_, encoding="gb2312") # no go
326
+ df_aligned.to_excel(file_dl_xlsx)
327
+
328
+ # return df_trimmed, plt
329
+
330
+ # return df_trimmed, plt, file_dl, file_dl_xlsx, df_aligned
331
+
332
+ # output_plot: gr.outputs.Image(type="auto", label="...")
333
+ return df_trimmed, output_plot, file_dl, file_dl_xlsx, df_aligned
334
+
335
+ # modi outputs
radiobee/text2lists.py CHANGED
@@ -1,13 +1,38 @@
1
  """Separate text to zh en lists."""
2
  # pylint: disable=
3
 
4
- from typing import Iterable, List, Tuple, Union # noqa
5
- from fastlid import fastlid
 
 
 
 
6
  from logzero import logger
7
 
 
 
 
8
 
9
- def text2lists(text: Union[Iterable[str], str]) -> List[Tuple[str, str]]:
10
- """Separate text to zh en lists."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  if not isinstance(text, str) and isinstance(text, Iterable):
12
  try:
13
  text = "\n".join(text)
@@ -15,30 +40,92 @@ def text2lists(text: Union[Iterable[str], str]) -> List[Tuple[str, str]]:
15
  logger.error(e)
16
  raise
17
 
18
- set_languages = ["en", "zh"]
19
- fastlid.set_languages = set_languages
 
 
 
 
20
  list1 = []
21
- list2 = [] # for determining en-zh or zh-en
22
- lang0, _ = fastlid(text[:15000])
23
- res = ""
24
- left = False # start with left list1
 
 
25
 
26
  for elm in [_ for _ in text.splitlines() if _.strip()]:
27
- lang, _ = fastlid(elm)
 
28
  if lang == lang0:
29
- res = res + "\n" + elm
30
  else:
31
- left = not left
32
  if left:
33
- list1.append(res.strip())
34
  else:
35
- list2.append(res.strip()) # strip first \n
36
- res = elm
 
 
37
  lang0 = lang
38
 
39
- # find offset
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- left = [] # noqa
42
- right = [] # noqa
 
 
 
 
 
 
 
43
 
44
- return [("", "")]
1
  """Separate text to zh en lists."""
2
  # pylint: disable=
3
 
4
+ # from typing import Tuple,
5
+ from typing import Iterable, List, Optional, Tuple, Union # noqa
6
+
7
+ import numpy as np
8
+
9
+ # from fastlid import fastlid
10
  from logzero import logger
11
 
12
+ from radiobee.lists2cmat import lists2cmat
13
+ from radiobee.detect import detect
14
+
15
 
16
+ def text2lists(
17
+ text: Union[Iterable[str], str],
18
+ set_languages: Optional[List[str]] = None,
19
+ ) -> Tuple[List[str], List[str]]:
20
+ """Separate text to zh en lists.
21
+
22
+ Args:
23
+ text: mixed text
24
+ set_languages: default to ["en", "zh"];
25
+ if set_languages is None:
26
+ set_languages = ["en", "zh"]
27
+
28
+ Attributes:
29
+ cmat: correlation matrix (len(list_l) x len(list_r))
30
+ before adjusting (shifting)
31
+ offset: plus, [""] * offset + list2
32
+ minus, [""] * (-offset) + list1
33
+ Returns:
34
+ two lists, best effort alignment
35
+ """
36
  if not isinstance(text, str) and isinstance(text, Iterable):
37
  try:
38
  text = "\n".join(text)
40
  logger.error(e)
41
  raise
42
 
43
+ # set_languages default to ["en", "zh"]
44
+ if set_languages is None:
45
+ set_languages = ["en", "zh"]
46
+
47
+ # fastlid.set_languages = set_languages
48
+
49
  list1 = []
50
+ list2 = []
51
+
52
+ # lang0, _ = fastlid(text[:15000])
53
+ lang0 = detect(text, set_languages)
54
+ res = []
55
+ left = True # start with left list1
56
 
57
  for elm in [_ for _ in text.splitlines() if _.strip()]:
58
+ # lang, _ = fastlid(elm)
59
+ lang = detect(elm, set_languages)
60
  if lang == lang0:
61
+ res.append(elm)
62
  else:
 
63
  if left:
64
+ list1.append("\n".join(res))
65
  else:
66
+ list2.append("\n".join(res))
67
+ left = not left
68
+
69
+ res = [elm]
70
  lang0 = lang
71
 
72
+ try:
73
+ # lang1, _ = fastlid(' '.join(list1))
74
+ lang1 = detect(" ".join(list1), set_languages)
75
+ except Exception as exc:
76
+ logger.error(exc)
77
+ lang1 = "en"
78
+ try:
79
+ # lang2, _ = fastlid(' '.join(list2))
80
+ lang2 = detect(" ".join(list2), set_languages)
81
+ except Exception as exc:
82
+ logger.error(exc)
83
+ lang2 = "en"
84
+
85
+ # find offset via diagonal(k),
86
+ len1, len2 = len(list1), len(list2)
87
+
88
+ # len2, len1 = cmat.shape
89
+ # len_r, len_c = cmat.shape
90
+ # ylim, xlim = cmat.shape
91
+ ylim, xlim = len2, len1 # check
92
+
93
+ # cmat dim: len1 x len2 or ylim x xlim
94
+ cmat = lists2cmat(list1, list2, lang1, lang2)
95
+
96
+ # sq_mean_pair = [(elm, np.square(cmat.diagonal(elm)).mean()) for elm in range(2 - ylim, xlim + 1)]
97
+ # df = pd.DataFrame(sq_mean_pair, columns=['offset', 'sq_mean'])
98
+ # df.plot.scatter('offset', 'sq_mean')
99
+ # optimum_offset = df.offset[df.sq_mean.argmax()]
100
+
101
+ # equiv to np.argmax(sq_mean) - (ylim - 2)
102
+ # locate max, -ylim + 2 ...xlim: range(1 - ylim, xlim)
103
+ # sqare sum
104
+
105
+ sq_mean = [np.square(cmat.diagonal(elm)).mean() for elm in range(1 - ylim, xlim - 1)]
106
+ # tot: xlim + ylim - 1
107
+
108
+ # temp = [np.square(cmat.diagonal(elm)) for elm in range(2 - ylim, xlim + 1)]
109
+ # sq_mean = [elm.mean() if np.any(elm) else 0.0 for elm in temp]
110
+
111
+ # plt.figure()
112
+ # plt.scatter(range(1 - ylim, xlim), sq_mean)
113
+
114
+ offset = np.argmax(sq_mean) - (ylim - 1)
115
+
116
+ text2lists.cmat = cmat
117
+ text2lists.offset = offset
118
+ text2lists.lang1 = lang1
119
+ text2lists.lang2 = lang2
120
 
121
+ # shift list1 if offsset >= 0, else shift list2
122
+ if offset > -1:
123
+ # list1a = list1[:]
124
+ # list2a = [""] * offset + list2
125
+ list2 = [""] * offset + list2
126
+ else:
127
+ list1 = [""] * (-offset) + list1
128
+ # list1a = [""] * (-offset) + list1
129
+ # list2a = list2[:]
130
 
131
+ return list1, list2
requirements.txt → requirements-man.txt RENAMED
File without changes
requirements-pipreqs.txt ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ brotli==1.0.9
2
+ cchardet==2.1.7
3
+ ConfigParser==5.2.0
4
+ cryptography==36.0.1
5
+ Cython==0.29.26
6
+ dl==0.1.0
7
+ docutils==0.17.1
8
+ fastlid==0.1.7
9
+ gradio==2.7.0
10
+ HTMLParser==0.0.2
11
+ importlib_metadata==4.8.1
12
+ ipaddr==2.2.0
13
+ joblib==1.0.1
14
+ keyring==23.5.0
15
+ lockfile==0.12.2
16
+ logzero==1.7.0
17
+ lxml==4.7.1
18
+ matplotlib==3.4.3
19
+ more_itertools==8.12.0
20
+ mypy_extensions==0.4.3
21
+ nltk==3.6.7
22
+ numpy==1.21.2
23
+ ordereddict==1.1
24
+ pandas==1.3.2
25
+ polyglot==16.7.4
26
+ protobuf==3.19.1
27
+ psutil==5.8.0
28
+ pyOpenSSL==21.0.0
29
+ pytest==6.2.5
30
+ pywin32==227
31
+ scikit_learn==1.0.2
32
+ seaborn==0.11.2
33
+ sentence_splitter==1.4
34
+ textacy==0.11.0
35
+ tqdm==4.62.2
36
+ typing_extensions==3.10.0.2
37
+ varname==0.8.1
38
+ wincertstore==0.2.1
39
+ xmlrpclib==1.0.1
40
+ zipp==3.6.0
run-radiobee.bat CHANGED
@@ -3,4 +3,7 @@ REM nodemon -V -w radiobee -x python -m radiobee
3
  REM nodemon -V -w radiobee -x py -3.8 -m radiobee
4
  REM nodemon -V -w radiobee -x "run-p pyright flake8 && py -3.8 -m radiobee"
5
  REM nodemon -V -w radiobee -x "run-p pyright-radiobee && py -3.8 -m radiobee"
6
- nodemon -V -w radiobee -x "pyright radiobee && py -3.8 -m radiobee"
 
 
 
3
  REM nodemon -V -w radiobee -x py -3.8 -m radiobee
4
  REM nodemon -V -w radiobee -x "run-p pyright flake8 && py -3.8 -m radiobee"
5
  REM nodemon -V -w radiobee -x "run-p pyright-radiobee && py -3.8 -m radiobee"
6
+ REM nodemon -V -w radiobee -x "pyright radiobee && py -3.8 -m radiobee"
7
+
8
+ REM E501 line-too-long, F401, unused import, W293 blank line contains whitespace
9
+ nodemon -V -w radiobee -x "flake8.exe --max-complexity=55 --ignore=E501,F401,W293 radiobee && py -3.8 -m radiobee"
tests/test_detect.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test detect."""
2
+ import pytest
3
+ from radiobee.detect import detect
4
+
5
+
6
+ @pytest.mark.parametrize(
7
+ "test_input,expected", [
8
+ ("", "en"),
9
+ (" ", "en"),
10
+ (" \n ", "en"),
11
+ ("注释", "zh"),
12
+ ]
13
+ )
14
+ def test_detect(test_input, expected):
15
+ """Test detect."""
16
+ assert detect(test_input) == expected
17
+
18
+ # expected set_languages[0], set_languages = ["en", "zh"]
19
+ assert detect(test_input, ["en", "zh"]) == expected
20
+
21
+
22
+ def test_detect_de():
23
+ """Test detect de."""
24
+ text = "4\u3000In der Beschränkung zeigt sich erst der Meister, / Und das Gesetz nur kann uns Freiheit geben. 参见http://www.business-it.nl/files/7d413a5dca62fc735a072b16fbf050b1-27.php." # noqa
25
+ assert detect(text) == "de"
26
+ assert detect(text, ["en", "zh"]) == "zh"
tests/test_main_single_input.py CHANGED
@@ -11,7 +11,8 @@ from logzero import logger
11
  from radiobee.files2df import files2df
12
  from radiobee.file2text import file2text
13
  from radiobee.lists2cmat import lists2cmat
14
- from radiobee.cmat2tset import cmat2tset
 
15
 
16
  file1loc = "data/test-dual.txt"
17
  file2loc = ""
@@ -34,6 +35,7 @@ def test_file2file1():
34
  text1 = file2text(file1)
35
  text2 = file2text(file2)
36
 
 
37
  lang1, _ = fastlid(text1)
38
  lang2, _ = fastlid(text2)
39
 
11
  from radiobee.files2df import files2df
12
  from radiobee.file2text import file2text
13
  from radiobee.lists2cmat import lists2cmat
14
+
15
+ # from radiobee.cmat2tset import cmat2tset
16
 
17
  file1loc = "data/test-dual.txt"
18
  file2loc = ""
35
  text1 = file2text(file1)
36
  text2 = file2text(file2)
37
 
38
+ fastlid.set_languages = ["en", "zh"]
39
  lang1, _ = fastlid(text1)
40
  lang2, _ = fastlid(text2)
41
 
tests/test_text2lists.py CHANGED
@@ -1,9 +1,50 @@
1
  """Test text2lists."""
2
- from radiobee.text2lists import text2lists
3
  from radiobee.loadtext import loadtext
 
4
 
5
 
6
  def test_text2lists():
7
  """Test text2lists data\test-dual.txt."""
8
  filename = r"data\test-dual.txt"
9
  text = loadtext(filename) # noqa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """Test text2lists."""
2
+ from pathlib import Path
3
  from radiobee.loadtext import loadtext
4
+ from radiobee.text2lists import text2lists
5
 
6
 
7
  def test_text2lists():
8
  """Test text2lists data\test-dual.txt."""
9
  filename = r"data\test-dual.txt"
10
  text = loadtext(filename) # noqa
11
+ l1, l2 = text2lists(text)
12
+ assert l2[0] in [""]
13
+ assert "国际\n中\n双语" in l1[0]
14
+
15
+
16
+ def test_shakespeare1000():
17
+ """Separate first 1000.
18
+
19
+ from pathlib import Path
20
+ import zipfile
21
+ dir_loc = r""
22
+ filename = r"莎士比亚 - 莎士比亚全集(套装共39本 英汉双语)-外语教学与研究出版社 (2016).txt.zip"
23
+ zfile = zipfile.ZipFile(Path(dir_loc) / filename)
24
+ res_bytes = zfile.read(zfile.infolist()[0])
25
+ encoding = cchardet.detect(res_bytes).get("encoding")
26
+
27
+ text1000 = []
28
+ line = 0
29
+ numb_lines = 4000
30
+ for elm in res_bytes.splitlines():
31
+ if elm.decode(encoding).strip():
32
+ text1000.append(elm.decode(encoding))
33
+ if line >= numb_lines - 1:
34
+ break
35
+ line += 1
36
+ Path(f"data/shakespeare-zh-en-{numb_lines}.txt").write_text("\n".join(text1000), encoding="utf8")
37
+
38
+ tset = cmat2test(cmat)
39
+ df = pd.DataFrame(tset).rename(columns=dict(zip(range(0, 3), ['x', 'y', 'cos'])))
40
+ plot_df(df)
41
+
42
+ """
43
+ # text1000a = Path("data/shakespeare-zh-en-1000.txt").read_text(encoding="utf8")
44
+ # text2000 = Path("data/shakespeare-zh-en-1000.txt").read_text(encoding="utf8")
45
+ text4000 = Path("data/shakespeare-zh-en-4000.txt").read_text(encoding="utf8")
46
+
47
+ # l1000a, l10002b = text2lists(text1000)
48
+ # l2000a, l2000b = text2lists(text2000)
49
+
50
+ l4000, r4000 = text2lists(text4000)