diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a08c56d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8-bom +insert_final_newline = true +trim_trailing_whitespace = true + +# CSharp code style settings: +[*.cs] +indent_size = 3 +csharp_space_between_method_call_parameter_list_parentheses = true +csharp_space_between_method_declaration_parameter_list_parentheses = true +csharp_space_between_square_brackets = true +csharp_space_after_keywords_in_control_flow_statements = false +csharp_space_between_parentheses = control_flow_statements, expressions \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e9b9ee1..97f47489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,91 @@ +### 2.14.0 + * FEATURE - Dramatically improved the text hooking capability for NGUI to much better handle static elements + +### 2.13.1 + * BUG FIX - Minor bug fix in rich text parser + * MISC - Enable Rich Text for TextMeshPro + * MISC - Improved whitespace handling with additional configuration option + +### 2.13.0 + * FEATURE - Support for older Unity Engine versions + * BUG FIX - Respect BepInEx logger config over own config + * BUG FIX - Fix exception that could occur in relation to NGUI + * MISC - Less leniency in what constitutes an error when translating + +### 2.12.0 + * FEATURE - General support for rich text in relation to UGUI and Utage + * FEATURE - Experimental support for custom fonts for UGUI + * CHANGE - Support only source languages with predefined character checks - for now (ja, zh-CN, zh-TW, ru, ko, en) + * CHANGE - Slightly different translation load priority from files + * BUG FIX - Dramatically improved resize behaviour for NGUI + * BUG FIX - Fixed a bug where hook overrides would not always be honored depending on mod load order + * MISC - 3 additional spam prevention checks + * MISC - Uses BepInLogger for BepInEx implementation (requires 4.0.0+) + * MISC - Redirect "GoogleTranslateHack" to "GoogleTranslate" because instructions were being distributed to use this, and it is not very friendly towards their APIs + +### 2.11.0 + * FEATURE - Support for legitimate Google Cloud Translate API (requires key) + * BUG FIX - Fixed situations where a text would not be translated on a component if a operation is ongoing on the component + * BUG FIX - Less delay on translation in certain situations + * MISC - Plugin seeded with ~10000 manually translated texts for commonly used translations to avoid hitting the configured endpoint too much (enable or disable with "UseStaticTranslations") + * Only applies when configured for Japanese to English (default) + +### 2.10.1 + * BUG FIX - Fix to prevent text overflow for large component for UGUI + +### 2.10.0 + * FEATURE - Support Yandex translate (requires key) + * FEATURE - Support Watson translate (requires key) + * FEATURE - Batching support for selected endpoints (makes translations much faster and requires lesser request) + * FEATURE - Experimental Utage support + * BUG FIX - Fixed minor bug during reading of text translation cache + * BUG FIX - Now escapes the '='-sign in the translation file, so texts containing this character can be translated + * BUG FIX - Fixed kana check when testing if a text is a candidate for translation + * MISC - No longer creating a new thread for each translation + * MISC - Proactive closing of unused TCP connections + * CONFIG - TrimAllText, to indicate whether whitespace in front of and behind translation candidates should be removed + * CONFIG - EnableBatching, to indicate whether batching should be enabled for supported endpoints + * CONFIG - EnableUIResizing, to indicate whether the plugin should make a "best attempt" at resizing the UI upon translation. Current only work for NGUI + +### 2.9.1 + * MISC - Added automatic configuration migration support + * Versions of this plugin were being distributed with predefined configuration to target "GoogleTranslateHack". The first time the plugin is run under this version, it will change this value back to the default. + +### 2.9.0 + * FEATURE - Installation as UnityInjector plugin + * FEATURE - Support Excite translate + * MISC - Better debugging capabilities with extra config options + +### 2.8.0 + * CHANGE - Whether SSL is enabled or not is now entirely based on chosen endpoint support + * FEATURE - Support for IMGUI translation texts with numbers + * FEATURE - Support for overwriting IMGUI hook events + * BUG FIX - Improved fix for gtrans (23.07.2018) by supporting persistent HTTP connections and cookies and recalculation of TKK and SSL + * BUG FIX - Fixed whitespace handling to honor configuration more appropriately + * BUG FIX - User-interaction (hotkeys) now works when in shutdown mode + * MISC - Prints out to console errors that occurrs during translation + * MISC - IMGUI is still disabled by default. Often other mods UI are implemented in IMGUI. Enabling it will allow those UIs to be translated as well. + * Simply change the config, such that: EnableIMGUI=True + +### 2.7.0 + * FEATURE - Additional installation instructions for standalone installation through ReiPatcher + * BUG FIX - Fixed a bug with NGUI that caused those texts not to be translated + * BUG FIX - Improved fix for gtrans (23.07.2018) + +### 2.6.0 + * FEATURE - Support for newer versions of unity engine (those including UnityEngine.CoreModule, etc. in Managed folder) + * BUG FIX - Fix for current issue with gtrans (23.07.2018) + * BUG FIX - Keeps functioning if web services fails, but no requests will be sent in such scenario. Texts will simply be translated from cache + * BUG FIX - Changed hooking, such that if text framework fails, the others wont also fail + * MISC - Concurrency now based on which type of endpoint. For gtrans it is set to 1 + * MISC - Bit more leniency in translation queue spam detection to prevent shutdown of plugin under normal circumstances + ### 2.5.0 - * Various new rate limiting patterns to prevent spam to configured translate endpoint - * Copy to clipboard feature + * FEATURE Copy to clipboard feature + * BUG FIX - Various new rate limiting patterns to prevent spam to configured translate endpoint ### 2.4.1 - * Disabled IMGUI hook due to bug + * BUG FIX - Disabled IMGUI hook due to bug ### 2.4.0 * CHANGE - Completely reworked configuration for more organization @@ -17,25 +99,25 @@ * BUG FIX - More leniency in allowing text formats (in translation files) to be included as translations ### 2.3.1 - * Fixed bug that caused the application to quit if any hooks were overriden. + * BUG FIX - Fixed bug that caused the application to quit if any hooks were overriden. ### 2.3.0 - * Allow usage of SSL - * Better dialogue caching handling. Often a dialogue might get translated multiple times because of small differences in the source text in regards to whitespace. + * FEATURE - Allow usage of SSL + * BUG FIX - Better dialogue caching handling. Often a dialogue might get translated multiple times because of small differences in the source text in regards to whitespace. ### 2.2.0 - * Added anti-spam safeguards to web requests that are sent. What it means: The plugin will no longer be able to attempt to translate a text it already considers translated. - * Changed internal programmatic HTTP service provider from .NET WebClient to Unity WWW. + * MISC - Added anti-spam safeguards to web requests that are sent. What it means: The plugin will no longer be able to attempt to translate a text it already considers translated. + * MISC - Changed internal programmatic HTTP service provider from .NET WebClient to Unity WWW. ### 2.1.0 - * Fixed a bug that could cause a StackOverflowException in unfortunate scenarios, if other mods interfered. - * Added configuration options to control which text frameworks to translate - * Added integration feature that allows other translation plugins to use this plugin as a fallback - * MUCH improved dialogue handling. Translations for dialogues should be significantly better than 2.0.1 + * FEATURE - Added configuration options to control which text frameworks to translate + * FEATURE - Added integration feature that allows other translation plugins to use this plugin as a fallback + * BUG FIX - Fixed a bug that could cause a StackOverflowException in unfortunate scenarios, if other mods interfered. + * BUG FIX - MUCH improved dialogue handling. Translations for dialogues should be significantly better than 2.0.1 ### 2.0.1 - * Changed configuration path so to not conflict with the configuration files that other mods uses, as it does not use the shared configuration system. The previous version could override configuration from other mods. - * General performance improvements. + * BUG FIX - Changed configuration path so to not conflict with the configuration files that other mods uses, as it does not use the shared configuration system. The previous version could override configuration from other mods. + * MISC - General performance improvements. ### 2.0.0 - * The initial release + * Initial release diff --git a/README.md b/README.md index 4e95466a..1db7b6fa 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -# XUnity Auto Translator +# XUnity Auto Translator ## Text Frameworks This is an auto translation mod that hooks into the unity game engine and attempts to provide translations for the following text frameworks for Unity: * UGUI * NGUI - * TextMeshPro * IMGUI + * TextMeshPro + * Utage (VN Game Engine) It does go to the internet, in order to provide the translation, so if you are not comfortable with that, dont use it. @@ -13,16 +14,18 @@ It does go to the internet, in order to provide the translation, so if you are n The mod can be installed into the following Plugin Managers: * [BepInEx](https://github.com/bbepis/BepInEx) * [IPA](https://github.com/Eusth/IPA) + * UnityInjector Installations instructions for both methods can be found below. +Additionally it can be installed without a dependency on a plugin manager through ReiPatcher. However, this approach is not recommended if you use one of the above mentioned Plugin Managers! + ## Configuration -The default configuration file, looks as such (2.4.0+): +The default configuration file, looks as such (2.6.0+): ```ini [Service] -Endpoint=GoogleTranslate ;Endpoint to use. Can be ["GoogleTranslate", "BaiduTranslate"] -EnableSSL=False ;Whether or not to use HTTPS endpoint over standard HTTP +Endpoint=GoogleTranslate ;Endpoint to use. Can be ["GoogleTranslate", "GoogleTranslateLegitimate", "BaiduTranslate", "YandexTranslate", "WatsonTranslate", "ExciteTranslate"] [General] Language=en ;The language to translate into @@ -42,18 +45,45 @@ AllowPluginHookOverride=True ;Allow other text translation plugins to overri [Behaviour] Delay=0 ;Delay to wait before attempting to translate a text in seconds MaxCharactersPerTranslation=150 ;Max characters per text to translate -IgnoreWhitespaceInDialogue=True ;Whether or not to ignore whitespace, such as newlines, in dialogue keys +IgnoreWhitespaceInDialogue=True ;Whether or not to ignore whitespace, including newlines, in dialogue keys +IgnoreWhitespaceInNGUI=True ;Whether or not to ignore whitespace, including newlines, in NGUI MinDialogueChars=20 ;The length of the text for it to be considered a dialogue ForceSplitTextAfterCharacters=0 ;Split text into multiple lines once the translated text exceeds this number of characters CopyToClipboard=False ;Whether or not to copy hooked texts to clipboard MaxClipboardCopyCharacters=450 ;Max number of characters to hook to clipboard at a time +EnableUIResizing=True ;Whether or not the plugin should provide a "best attempt" at resizing UI components upon translation. Only work for NGUI +EnableBatching=True ;Indicates whether batching of translations should be enabled for supported endpoints +TrimAllText=True ;Indicates whether spaces in front and behind translation candidates should be removed before translation +UseStaticTranslations=True ;Indicates whether or not to use translations from the included static translation cache +OverrideFont= ;Overrides the fonts used for texts when updating text components. NOTE: Only works for UGUI +WhitespaceRemovalStrategy=TrimPerNewline ;Indicates how whitespace/newline removal should be handled before attempting translation. Can be ["TrimPerNewline", "AllOccurrences"] + +[Http] +UserAgent= ;Override the user agent used by APIs requiring a user agent + +[GoogleLegitimate] +GoogleAPIKey= ;OPTIONAL, needed if GoogleTranslateLegitimate is configured [Baidu] BaiduAppId= ;OPTIONAL, needed if BaiduTranslate is configured BaiduAppSecret= ;OPTIONAL, needed if BaiduTranslate is configured +[Yandex] +YandexAPIKey= ;OPTIONAL, needed if YandexTranslate is configured + +[Watson] +WatsonAPIUrl= ;OPTIONAL, needed if WatsonTranslate is configured +WatsonAPIUsername= ;OPTIONAL, needed if WatsonTranslate is configured +WatsonAPIPassword= ;OPTIONAL, needed if WatsonTranslate is configured + [Debug] EnablePrintHierarchy=False ;Used for debugging +EnableConsole=False ;Enables the console. Do not enable if other plugins (managers) handles this +EnableLog=False ;Enables extra logging for debugging purposes + +[Migrations] +Enable=True ;Used to enable automatic migrations of this configuration file +Tag=2.9.0 ;Tag representing the last version this plugin was executed under. Do not edit ``` ## Key Mapping @@ -68,10 +98,10 @@ The plugin can be installed in following ways: ### BepInEx Plugin REQUIRES: [BepInEx plugin manager](https://github.com/bbepis/BepInEx) (follow its installation instructions first!). - 1. Download XUnity.AutoTranslator-BepIn-{VERSION}.zip from [releases](https://github.com/bbepis/XUnity.AutoTranslator/releases). + 1. Download XUnity.AutoTranslator-BepIn-{VERSION}.zip from [releases](../../releases). 2. Extract directly into the game directory, such that the plugin dlls are placed in BepInEx folder. -The file structure should likke like this: +The file structure should like like this: ``` {GameDirectory}/BepInEx/XUnity.AutoTranslator.Plugin.Core.dll {GameDirectory}/BepInEx/XUnity.AutoTranslator.Plugin.Core.BepInEx.dll @@ -82,10 +112,10 @@ The file structure should likke like this: ### IPA Plugin REQUIRES: [IPA plugin manager](https://github.com/Eusth/IPA) (follow its installation instructions first!). - 1. Download XUnity.AutoTranslator-IPA-{VERSION}.zip from [releases](https://github.com/bbepis/XUnity.AutoTranslator/releases). + 1. Download XUnity.AutoTranslator-IPA-{VERSION}.zip from [releases](../../releases). 2. Extract directly into the game directory, such that the plugin dlls are placed in Plugins folder. -The file structure should likke like this +The file structure should like like this ``` {GameDirectory}/Plugins/XUnity.AutoTranslator.Plugin.Core.dll {GameDirectory}/Plugins/XUnity.AutoTranslator.Plugin.Core.IPA.dll @@ -94,6 +124,50 @@ The file structure should likke like this {GameDirectory}/Plugins/Translation/AnyTranslationFile.txt (this files will be auto generated by plugin!) ``` +### UnityInjector Plugin +REQUIRES: UnityInjector (follow its installation instructions first!). + + 1. Download XUnity.AutoTranslator-UnityInjector-{VERSION}.zip from [releases](../../releases). + 2. Extract directly into the game directory, such that the plugin dlls are placed in UnityInjector folder. **This may not be game root directory!** + +The file structure should like like this +``` +{GameDirectory}/UnityInjector/XUnity.AutoTranslator.Plugin.Core.dll +{GameDirectory}/UnityInjector/XUnity.AutoTranslator.Plugin.Core.UnityInjector.dll +{GameDirectory}/UnityInjector/0Harmony.dll +{GameDirectory}/UnityInjector/ExIni.dll +{GameDirectory}/UnityInjector/Translation/AnyTranslationFile.txt (this files will be auto generated by plugin!) + ``` + +### Standalone Installation (ReiPatcher) +REQUIRES: Nothing, ReiPatcher is provided by this download. + + 1. Download XUnity.AutoTranslator-ReiPatcher-{VERSION}.zip from [releases](../../releases). + 2. Extract directly into the game directory, such that "SetupReiPatcherAndAutoTranslator.exe" is placed alongside other exe files. + 3. Execute "SetupReiPatcherAndAutoTranslator.exe". This will setup up ReiPatcher correctly. + 4. Execute the shortcut {GameExeName}.lnk that was created besides existing executables. This will patch and launch the game. + 5. From now on you can launch the game from the {GameExeName}.exe instead. + +The file structure should like like this +``` +{GameDirectory}/ReiPatcher/Patches/XUnity.AutoTranslator.Patcher.dll +{GameDirectory}/ReiPatcher/ExIni.dll +{GameDirectory}/ReiPatcher/Mono.Cecil.dll +{GameDirectory}/ReiPatcher/Mono.Cecil.Inject.dll +{GameDirectory}/ReiPatcher/Mono.Cecil.Mdb.dll +{GameDirectory}/ReiPatcher/Mono.Cecil.Pdb.dll +{GameDirectory}/ReiPatcher/Mono.Cecil.Rocks.dll +{GameDirectory}/ReiPatcher/ReiPatcher.exe +{GameDirectory}/{GameExeName}_Data/Managed/ReiPatcher.exe +{GameDirectory}/{GameExeName}_Data/Managed/XUnity.AutoTranslator.Plugin.Core.dll +{GameDirectory}/{GameExeName}_Data/Managed/0Harmony.dll +{GameDirectory}/{GameExeName}_Data/Managed/ExIni.dll +{GameDirectory}/AutoTranslator/AnyTranslationFile.txt (this files will be auto generated by plugin!) + ``` + +## Translating Mods +Often other mods UI are implemented through IMGUI. As you can see above, this is disabled by default. By changing the "EnableIMGUI" value to "True", it will start translating IMGUI as well, which likely means that other mods UI will be translated. + ## Integrating with Auto Translator I have implemented a system that allows other dedicated translation mods to integrate with XUnity AutoTranslator. @@ -109,4 +183,5 @@ Here's how it works, and what is required: 1. UGUI: public static event Func OnUnableToTranslateUGUI 2. TextMeshPro: public static event Func OnUnableToTranslateTextMeshPro 3. NGUI: public static event Func OnUnableToTranslateNGUI + 3. IMGUI: public static event Func OnUnableToTranslateIMGUI * Also, the events can be either instance based or static. diff --git a/XUnity.AutoTranslator.sln b/XUnity.AutoTranslator.sln index a80c5519..06ffcb87 100644 --- a/XUnity.AutoTranslator.sln +++ b/XUnity.AutoTranslator.sln @@ -11,9 +11,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnity.AutoTranslator.Plugi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnity.AutoTranslator.Plugin.IPA", "src\XUnity.AutoTranslator.Plugin.IPA\XUnity.AutoTranslator.Plugin.IPA.csproj", "{C749698C-9E49-4CC3-8B45-62AE3AD0C938}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XUnity.AutoTranslator.Patcher", "src\XUnity.AutoTranslator.Patcher\XUnity.AutoTranslator.Patcher.csproj", "{0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnity.AutoTranslator.Patcher", "src\XUnity.AutoTranslator.Patcher\XUnity.AutoTranslator.Patcher.csproj", "{0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XUnity.AutoTranslator.Setup", "src\XUnity.AutoTranslator.Setup\XUnity.AutoTranslator.Setup.csproj", "{86BF1F46-44C1-4301-8314-6EC32F74575F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnity.AutoTranslator.Setup", "src\XUnity.AutoTranslator.Setup\XUnity.AutoTranslator.Setup.csproj", "{86BF1F46-44C1-4301-8314-6EC32F74575F}" + ProjectSection(ProjectDependencies) = postProject + {718A3B1D-A5E5-4223-AD53-45C60C874150} = {718A3B1D-A5E5-4223-AD53-45C60C874150} + {0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD} = {0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XUnity.AutoTranslator.Plugin.UnityInjector", "src\XUnity.AutoTranslator.Plugin.UnityInjector\XUnity.AutoTranslator.Plugin.UnityInjector.csproj", "{12F1D16B-B8E1-4A9D-B65A-044650F15440}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ACADAE2C-1642-428A-84D4-CC53E24F1348}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -41,6 +51,10 @@ Global {86BF1F46-44C1-4301-8314-6EC32F74575F}.Debug|Any CPU.Build.0 = Debug|Any CPU {86BF1F46-44C1-4301-8314-6EC32F74575F}.Release|Any CPU.ActiveCfg = Release|Any CPU {86BF1F46-44C1-4301-8314-6EC32F74575F}.Release|Any CPU.Build.0 = Release|Any CPU + {12F1D16B-B8E1-4A9D-B65A-044650F15440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12F1D16B-B8E1-4A9D-B65A-044650F15440}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12F1D16B-B8E1-4A9D-B65A-044650F15440}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12F1D16B-B8E1-4A9D-B65A-044650F15440}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -51,6 +65,7 @@ Global {C749698C-9E49-4CC3-8B45-62AE3AD0C938} = {0F9B38FC-4E57-4B83-AF0B-0993B8470823} {0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD} = {0F9B38FC-4E57-4B83-AF0B-0993B8470823} {86BF1F46-44C1-4301-8314-6EC32F74575F} = {0F9B38FC-4E57-4B83-AF0B-0993B8470823} + {12F1D16B-B8E1-4A9D-B65A-044650F15440} = {0F9B38FC-4E57-4B83-AF0B-0993B8470823} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EE803FED-4447-4D19-B3D6-88C56E8DFCCA} diff --git a/libs/BepInEx.dll b/libs/BepInEx.dll index 433ca33a..fda35f29 100644 Binary files a/libs/BepInEx.dll and b/libs/BepInEx.dll differ diff --git a/libs/Mono.Cecil.Mdb.dll b/libs/Mono.Cecil.Mdb.dll new file mode 100644 index 00000000..dc2ce20d Binary files /dev/null and b/libs/Mono.Cecil.Mdb.dll differ diff --git a/libs/Mono.Cecil.Pdb.dll b/libs/Mono.Cecil.Pdb.dll new file mode 100644 index 00000000..ef5c600c Binary files /dev/null and b/libs/Mono.Cecil.Pdb.dll differ diff --git a/libs/Mono.Cecil.Rocks.dll b/libs/Mono.Cecil.Rocks.dll new file mode 100644 index 00000000..de1446cf Binary files /dev/null and b/libs/Mono.Cecil.Rocks.dll differ diff --git a/libs/UnityInjector.dll b/libs/UnityInjector.dll new file mode 100644 index 00000000..d085ddf3 Binary files /dev/null and b/libs/UnityInjector.dll differ diff --git a/src/XUnity.AutoTranslator.Patcher/Patcher.cs b/src/XUnity.AutoTranslator.Patcher/Patcher.cs index e39a08ed..43588887 100644 --- a/src/XUnity.AutoTranslator.Patcher/Patcher.cs +++ b/src/XUnity.AutoTranslator.Patcher/Patcher.cs @@ -14,8 +14,8 @@ namespace XUnity.AutoTranslator.Patcher public class Patcher : PatchBase { private static readonly HashSet EntryClasses = new HashSet { "Display", "Input" }; - private AssemblyDefinition _hookAssembly; + private string _assemblyName; public override string Name { @@ -29,20 +29,29 @@ public override string Version { get { - return "2.0.1"; + return "2.14.0"; } } public override void PrePatch() { - RPConfig.RequestAssembly( "UnityEngine.dll" ); + if( ManagedDllExists( "UnityEngine.CoreModule.dll" ) ) + { + RPConfig.RequestAssembly( "UnityEngine.CoreModule.dll" ); + _assemblyName = "UnityEngine.CoreModule"; + } + else if( ManagedDllExists( "UnityEngine.dll" ) ) + { + RPConfig.RequestAssembly( "UnityEngine.dll" ); + _assemblyName = "UnityEngine"; + } _hookAssembly = LoadAssembly( "XUnity.AutoTranslator.Plugin.Core.dll" ); } public override bool CanPatch( PatcherArguments args ) { - return args.Assembly.Name.Name == "UnityEngine" && !HasAttribute( this, args.Assembly, "XUnity.AutoTranslator.Plugin.Core" ); + return ( args.Assembly.Name.Name == _assemblyName ) && !HasAttribute( this, args.Assembly, "XUnity.AutoTranslator.Plugin.Core" ); } public override void Patch( PatcherArguments args ) @@ -66,6 +75,12 @@ public override void Patch( PatcherArguments args ) SetPatchedAttribute( args.Assembly, "XUnity.AutoTranslator.Plugin.Core" ); } + public bool ManagedDllExists( string name ) + { + string path = Path.Combine( RPConfig.ConfigFile.GetSection( "ReiPatcher" ).GetKey( "AssembliesDir" ).Value, name ); + return File.Exists( path ); + } + public static AssemblyDefinition LoadAssembly( string name ) { string path = Path.Combine( RPConfig.ConfigFile.GetSection( "ReiPatcher" ).GetKey( "AssembliesDir" ).Value, name ); diff --git a/src/XUnity.AutoTranslator.Patcher/XUnity.AutoTranslator.Patcher.csproj b/src/XUnity.AutoTranslator.Patcher/XUnity.AutoTranslator.Patcher.csproj index 138f5f8f..4b945cfc 100644 --- a/src/XUnity.AutoTranslator.Patcher/XUnity.AutoTranslator.Patcher.csproj +++ b/src/XUnity.AutoTranslator.Patcher/XUnity.AutoTranslator.Patcher.csproj @@ -4,10 +4,6 @@ net35 - - - - ..\..\libs\ExIni.dll diff --git a/src/XUnity.AutoTranslator.Plugin.BepIn/AutoTranslatorPlugin.cs b/src/XUnity.AutoTranslator.Plugin.BepIn/AutoTranslatorPlugin.cs index 03c4b3c8..0aecad5d 100644 --- a/src/XUnity.AutoTranslator.Plugin.BepIn/AutoTranslatorPlugin.cs +++ b/src/XUnity.AutoTranslator.Plugin.BepIn/AutoTranslatorPlugin.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Text; -using BepInEx; using ExIni; using XUnity.AutoTranslator.Plugin.Core; using XUnity.AutoTranslator.Plugin.Core.Configuration; @@ -11,8 +10,8 @@ namespace XUnity.AutoTranslator.Plugin.BepIn { - [BepInPlugin( GUID: PluginData.Identifier, Name: PluginData.Name, Version: PluginData.Version )] - public class AutoTranslatorPlugin : BaseUnityPlugin, IConfiguration + [BepInEx.BepInPlugin( GUID: PluginData.Identifier, Name: PluginData.Name, Version: PluginData.Version )] + public class AutoTranslatorPlugin : BepInEx.BaseUnityPlugin, IConfiguration { private IniFile _file; private string _configPath; @@ -22,6 +21,7 @@ public AutoTranslatorPlugin() { _dataFolder = "BepInEx"; _configPath = Path.Combine( _dataFolder, "AutoTranslatorConfig.ini" ); + Logger.Current = new BepInLogger(); } public IniFile Preferences diff --git a/src/XUnity.AutoTranslator.Plugin.BepIn/BepInLogger.cs b/src/XUnity.AutoTranslator.Plugin.BepIn/BepInLogger.cs new file mode 100644 index 00000000..f90d0584 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.BepIn/BepInLogger.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core; + +namespace XUnity.AutoTranslator.Plugin.BepIn +{ + public class BepInLogger : Logger + { + public BepInLogger() + { + RespectSettings = false; + } + + protected override void Log( LogLevel level, string message ) + { + BepInEx.Logger.CurrentLogger.Log( Convert( level ), "[XUnity.AutoTranslator] " + message ); + } + + public BepInEx.Logging.LogLevel Convert( LogLevel level ) + { + switch( level ) + { + case LogLevel.Debug: + return BepInEx.Logging.LogLevel.Debug; + case LogLevel.Info: + return BepInEx.Logging.LogLevel.Info; + case LogLevel.Warn: + return BepInEx.Logging.LogLevel.Warning; + case LogLevel.Error: + return BepInEx.Logging.LogLevel.Error; + default: + return BepInEx.Logging.LogLevel.None; + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj b/src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj index fd4d8b1e..4150b699 100644 --- a/src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj +++ b/src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj @@ -1,29 +1,27 @@ - + net35 - 2.5.0.0 - 2.5.0.0 - 2.5.0 + 2.14.0 - + - - ..\..\libs\BepInEx.dll - - - ..\..\libs\ExIni.dll - - - ..\..\libs\UnityEngine.dll - - - ..\..\libs\UnityEngine.UI.dll - + + ..\..\libs\BepInEx.dll + + + ..\..\libs\ExIni.dll + + + ..\..\libs\UnityEngine.dll + + + ..\..\libs\UnityEngine.UI.dll + @@ -33,7 +31,7 @@ - + diff --git a/src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs b/src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs index 28204197..bd373086 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs @@ -24,11 +24,17 @@ using XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI; using UnityEngine.SceneManagement; using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Debugging; +using XUnity.AutoTranslator.Plugin.Core.Batching; +using Harmony; +using XUnity.AutoTranslator.Plugin.Core.Parsing; namespace XUnity.AutoTranslator.Plugin.Core { public class AutoTranslationPlugin : MonoBehaviour { + private static readonly char[][] TranslationSplitters = new char[][] { new char[] { '\t' }, new char[] { '=' } }; + /// /// Allow the instance to be accessed statically, as only one will exist. /// @@ -39,11 +45,14 @@ public class AutoTranslationPlugin : MonoBehaviour /// private List _completedJobs = new List(); private Dictionary _unstartedJobs = new Dictionary(); + private Dictionary _ongoingJobs = new Dictionary(); /// /// All the translations are stored in this dictionary. /// + private Dictionary _staticTranslations = new Dictionary(); private Dictionary _translations = new Dictionary(); + private Dictionary _reverseTranslations = new Dictionary(); /// /// These are the new translations that has not yet been persisted to the file system. @@ -51,7 +60,6 @@ public class AutoTranslationPlugin : MonoBehaviour private object _writeToFileSync = new object(); private Dictionary _newTranslations = new Dictionary(); private HashSet _newUntranslated = new HashSet(); - private HashSet _translatedTexts = new HashSet(); /// /// Keeps track of things to copy to clipboard. @@ -70,35 +78,104 @@ public class AutoTranslationPlugin : MonoBehaviour /// the translation plugin. /// private HashSet _ongoingOperations = new HashSet(); - private HashSet _startedOperationsForNonStabilizableComponents = new HashSet(); /// /// This function will check if there are symbols of a given language contained in a string. /// private Func _symbolCheck; + private object _advEngine; + private float? _nextAdvUpdate; + + private IKnownEndpoint _endpoint; + private int[] _currentTranslationsQueuedPerSecondRollingWindow = new int[ Settings.TranslationQueueWatchWindow ]; private float? _timeExceededThreshold; + private float _translationsQueuedPerSecond; private bool _isInTranslatedMode = true; private bool _hooksEnabled = true; + private bool _batchLogicHasFailed = false; + + private int _availableBatchOperations = Settings.MaxAvailableBatchOperations; + private float _batchOperationSecondCounter = 0; + + private string _previouslyQueuedText = null; + private int _concurrentStaggers = 0; + + private int _frameForLastQueuedTranslation = -1; + private int _consecutiveFramesTranslated = 0; + + private int _secondForQueuedTranslation = -1; + private int _consecutiveSecondsTranslated = 0; + + private bool _changeFont = false; + private bool _initialized = false; public void Initialize() { Current = this; + if( Logger.Current == null ) + { + Logger.Current = new ConsoleLogger(); + } - Settings.Configure(); + try + { + Settings.Configure(); + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred during configuration. Shutting plugin down." ); + + _endpoint = null; + Settings.IsShutdown = true; + + return; + } - HooksSetup.InstallHooks( Override_TextChanged ); + if( Settings.EnableConsole ) DebugConsole.Enable(); - AutoTranslateClient.Configure(); + HooksSetup.InstallHooks(); + + try + { + _endpoint = KnownEndpoints.FindEndpoint( Settings.ServiceEndpoint ); + } + catch( Exception e ) + { + Logger.Current.Error( e, "An unexpected error occurred during initialization of endpoint." ); + } + + if( !TextHelper.IsFromLanguageSupported( Settings.FromLanguage ) ) + { + Logger.Current.Error( $"The plugin has been configured to use the 'FromLanguage={Settings.FromLanguage}'. This language is not supported. Shutting plugin down." ); + + _endpoint = null; + Settings.IsShutdown = true; + } _symbolCheck = TextHelper.GetSymbolCheck( Settings.FromLanguage ); + if( !string.IsNullOrEmpty( Settings.OverrideFont ) ) + { + var available = Font.GetOSInstalledFontNames(); + if( !available.Contains( Settings.OverrideFont ) ) + { + Logger.Current.Error( $"The specified override font is not available. Available fonts: " + string.Join( ", ", available ) ); + Settings.OverrideFont = null; + } + else + { + _changeFont = true; + } + } + LoadTranslations(); + LoadStaticTranslations(); // start a thread that will periodically removed unused references - var t1 = new Thread( RemovedUnusedReferences ); + var t1 = new Thread( MaintenanceLoop ); t1.IsBackground = true; t1.Start(); @@ -108,17 +185,13 @@ public void Initialize() t2.Start(); } - private string[] GetTranslationFiles() + private IEnumerable GetTranslationFiles() { - return Directory.GetFiles( Path.Combine( Config.Current.DataPath, Settings.TranslationDirectory ), $"*.txt", SearchOption.AllDirectories ) // FIXME: Add $"*{Language}.txt" - .Union( new[] { Settings.AutoTranslationsFilePath } ) - .Select( x => x.Replace( "/", "\\" ) ) - .Distinct() - .OrderBy( x => x ) - .ToArray(); + return Directory.GetFiles( Path.Combine( Config.Current.DataPath, Settings.TranslationDirectory ), $"*.txt", SearchOption.AllDirectories ) + .Select( x => x.Replace( "/", "\\" ) ); } - private void RemovedUnusedReferences( object state ) + private void MaintenanceLoop( object state ) { while( true ) { @@ -128,12 +201,10 @@ private void RemovedUnusedReferences( object state ) } catch( Exception e ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An unexpected error occurred while removing GC'ed resources." + Environment.NewLine + e ); - } - finally - { - Thread.Sleep( 1000 * 60 ); + Logger.Current.Error( e, "An unexpected error occurred while removing GC'ed resources." ); } + + Thread.Sleep( 1000 * 60 ); } } @@ -170,7 +241,7 @@ private void SaveTranslationsLoop( object state ) } catch( Exception e ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error occurred while saving translations to disk. " + Environment.NewLine + e ); + Logger.Current.Error( e, "An error occurred while saving translations to disk." ); } } @@ -186,61 +257,242 @@ private void LoadTranslations() Directory.CreateDirectory( Path.Combine( Config.Current.DataPath, Settings.TranslationDirectory ) ); Directory.CreateDirectory( Path.GetDirectoryName( Path.Combine( Config.Current.DataPath, Settings.OutputFile ) ) ); - foreach( var fullFileName in GetTranslationFiles() ) + var mainTranslationFile = Settings.AutoTranslationsFilePath.Replace( "/", "\\" ); + LoadTranslationsInFile( mainTranslationFile ); + foreach( var fullFileName in GetTranslationFiles().Reverse().Except( new[] { mainTranslationFile } ) ) { - if( File.Exists( fullFileName ) ) + LoadTranslationsInFile( fullFileName ); + } + } + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred while loading translations." ); + } + } + + private void LoadTranslationsInFile( string fullFileName ) + { + if( File.Exists( fullFileName ) ) + { + Logger.Current.Debug( $"Loading translations from {fullFileName}." ); + + string[] translations = File.ReadAllLines( fullFileName, Encoding.UTF8 ); + foreach( string translation in translations ) + { + for( int i = 0 ; i < TranslationSplitters.Length ; i++ ) + { + var splitter = TranslationSplitters[ i ]; + string[] kvp = translation.Split( splitter, StringSplitOptions.None ); + if( kvp.Length == 2 ) { - string[] translations = File.ReadAllLines( fullFileName, Encoding.UTF8 ); - foreach( string translation in translations ) - { - string[] kvp = translation.Split( new char[] { '=', '\t' }, StringSplitOptions.None ); - if( kvp.Length >= 2 ) - { - string key = TextHelper.Decode( kvp[ 0 ].Trim() ); - string value = TextHelper.Decode( kvp[ 1 ].Trim() ); + string key = TextHelper.Decode( kvp[ 0 ].TrimIfConfigured() ); + string value = TextHelper.Decode( kvp[ 1 ].TrimIfConfigured() ); - if( !string.IsNullOrEmpty( key ) && !string.IsNullOrEmpty( value ) ) - { - var translationKey = new TranslationKeys( key ); - AddTranslation( translationKey, value ); - } - } + if( !string.IsNullOrEmpty( key ) && !string.IsNullOrEmpty( value ) && IsTranslatable( key ) ) + { + AddTranslation( key, value ); + break; } } } } } - catch( Exception e ) + } + + private void LoadStaticTranslations() + { + if( Settings.UseStaticTranslations && Settings.FromLanguage == Settings.DefaultFromLanguage && Settings.Language == Settings.DefaultLanguage ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error occurred while loading translations. " + Environment.NewLine + e ); + var tab = new char[] { '\t' }; + var equals = new char[] { '=' }; + var splitters = new char[][] { tab, equals }; + + // load static translations from previous titles + string[] translations = Properties.Resources.StaticTranslations.Split( new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries ); + foreach( string translation in translations ) + { + for( int i = 0 ; i < splitters.Length ; i++ ) + { + var splitter = splitters[ i ]; + string[] kvp = translation.Split( splitter, StringSplitOptions.None ); + if( kvp.Length >= 2 ) + { + string key = TextHelper.Decode( kvp[ 0 ].TrimIfConfigured() ); + string value = TextHelper.Decode( kvp[ 1 ].TrimIfConfigured() ); + + if( !string.IsNullOrEmpty( key ) && !string.IsNullOrEmpty( value ) ) + { + _staticTranslations[ key ] = value; + break; + } + } + } + } } } - private TranslationJob GetOrCreateTranslationJobFor( TranslationKeys key ) + private TranslationJob GetOrCreateTranslationJobFor( object ui, TranslationKey key, TranslationContext context ) { - if( _unstartedJobs.TryGetValue( key.ForcedRelevantKey, out TranslationJob job ) ) + var lookupKey = key.GetDictionaryLookupKey(); + + if( _unstartedJobs.TryGetValue( lookupKey, out TranslationJob unstartedJob ) ) + { + unstartedJob.Associate( context ); + return unstartedJob; + } + + if( _ongoingJobs.TryGetValue( lookupKey, out TranslationJob ongoingJob ) ) { - return job; + ongoingJob.Associate( context ); + return ongoingJob; } foreach( var completedJob in _completedJobs ) { - if( completedJob.Keys.ForcedRelevantKey == key.ForcedRelevantKey ) + if( completedJob.Key.GetDictionaryLookupKey() == lookupKey ) { + completedJob.Associate( context ); return completedJob; } } - job = new TranslationJob( key ); - _unstartedJobs.Add( key.ForcedRelevantKey, job ); + Logger.Current.Debug( "Queued translation for: " + lookupKey ); + + ongoingJob = new TranslationJob( key ); + if( ui != null ) + { + ongoingJob.OriginalSources.Add( ui ); + } + ongoingJob.Associate( context ); + + _unstartedJobs.Add( lookupKey, ongoingJob ); + CheckStaggerText( lookupKey ); + CheckConsecutiveFrames(); + CheckConsecutiveSeconds(); CheckThresholds(); - return job; + return ongoingJob; + } + + private void CheckConsecutiveSeconds() + { + var currentSecond = (int)Time.time; + var lastSecond = currentSecond - 1; + + if( lastSecond == _secondForQueuedTranslation ) + { + // we also queued something last frame, lets increment our counter + _consecutiveSecondsTranslated++; + + if( _consecutiveSecondsTranslated > Settings.MaximumConsecutiveSecondsTranslated ) + { + // Shutdown, this wont be tolerated!!! + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + + Settings.IsShutdown = true; + Logger.Current.Error( $"SPAM DETECTED: Translations were queued every second for more than {Settings.MaximumConsecutiveSecondsTranslated} consecutive seconds. Shutting down plugin." ); + } + + } + else if( currentSecond == _secondForQueuedTranslation ) + { + // do nothing, there may be multiple translations per frame, that wont increase this counter + } + else + { + // but if multiple Update frames has passed, we will reset the counter + _consecutiveSecondsTranslated = 0; + } + + _secondForQueuedTranslation = currentSecond; + } + + private void CheckConsecutiveFrames() + { + var currentFrame = Time.frameCount; + var lastFrame = currentFrame - 1; + + if( lastFrame == _frameForLastQueuedTranslation ) + { + // we also queued something last frame, lets increment our counter + _consecutiveFramesTranslated++; + + if( _consecutiveFramesTranslated > Settings.MaximumConsecutiveFramesTranslated ) + { + // Shutdown, this wont be tolerated!!! + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + + Settings.IsShutdown = true; + Logger.Current.Error( $"SPAM DETECTED: Translations were queued every frame for more than {Settings.MaximumConsecutiveFramesTranslated} consecutive frames. Shutting down plugin." ); + } + + } + else if( currentFrame == _frameForLastQueuedTranslation ) + { + // do nothing, there may be multiple translations per frame, that wont increase this counter + } + else if( _consecutiveFramesTranslated > 0 ) + { + // but if multiple Update frames has passed, we will reset the counter + _consecutiveFramesTranslated--; + } + + _frameForLastQueuedTranslation = currentFrame; + } + + public void PeriodicResetFrameCheck() + { + var currentSecond = (int)Time.time; + if( currentSecond % 100 == 0 ) + { + _consecutiveFramesTranslated = 0; + } + } + + private void CheckStaggerText( string untranslatedText ) + { + if( _previouslyQueuedText != null ) + { + if( untranslatedText.StartsWith( _previouslyQueuedText ) ) + { + _concurrentStaggers++; + if( _concurrentStaggers > Settings.MaximumStaggers ) + { + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + + Settings.IsShutdown = true; + Logger.Current.Error( $"SPAM DETECTED: Text that is 'scrolling in' is being translated. Disable that feature. Shutting down plugin." ); + } + } + else + { + _concurrentStaggers = 0; + } + + } + _previouslyQueuedText = untranslatedText; } private void CheckThresholds() { + if( _unstartedJobs.Count > Settings.MaxUnstartedJobs ) + { + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + + Settings.IsShutdown = true; + Logger.Current.Error( $"SPAM DETECTED: More than {Settings.MaxUnstartedJobs} queued for translations due to unknown reasons. Shutting down plugin." ); + } + var previousIdx = ( (int)( Time.time - Time.deltaTime ) ) % Settings.TranslationQueueWatchWindow; var newIdx = ( (int)Time.time ) % Settings.TranslationQueueWatchWindow; if( previousIdx != newIdx ) @@ -250,21 +502,22 @@ private void CheckThresholds() _currentTranslationsQueuedPerSecondRollingWindow[ newIdx ]++; var translationsInWindow = _currentTranslationsQueuedPerSecondRollingWindow.Sum(); - var translationsPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow; - if( translationsPerSecond > Settings.MaxTranslationsQueuedPerSecond ) + _translationsQueuedPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow; + if( _translationsQueuedPerSecond > Settings.MaxTranslationsQueuedPerSecond ) { if( !_timeExceededThreshold.HasValue ) { _timeExceededThreshold = Time.time; } - if( Time.time - _timeExceededThreshold.Value > Settings.MaxSecondsAboveTranslationThreshold || _unstartedJobs.Count > Settings.MaxUnstartedJobs ) + if( Time.time - _timeExceededThreshold.Value > Settings.MaxSecondsAboveTranslationThreshold ) { _unstartedJobs.Clear(); _completedJobs.Clear(); + _ongoingJobs.Clear(); Settings.IsShutdown = true; - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: Shutting down... spam detected." ); + Logger.Current.Error( $"SPAM DETECTED: More than {Settings.MaxTranslationsQueuedPerSecond} translations per seconds queued for a {Settings.MaxSecondsAboveTranslationThreshold} second period. Shutting down plugin." ); } } else @@ -273,6 +526,21 @@ private void CheckThresholds() } } + private void IncrementBatchOperations() + { + _batchOperationSecondCounter += Time.deltaTime; + + if( _batchOperationSecondCounter > Settings.IncreaseBatchOperationsEvery ) + { + if( _availableBatchOperations < Settings.MaxAvailableBatchOperations ) + { + _availableBatchOperations++; + } + + _batchOperationSecondCounter = 0; + } + } + private void ResetThresholdTimerIfRequired() { var previousIdx = ( (int)( Time.time - Time.deltaTime ) ) % Settings.TranslationQueueWatchWindow; @@ -283,60 +551,91 @@ private void ResetThresholdTimerIfRequired() } var translationsInWindow = _currentTranslationsQueuedPerSecondRollingWindow.Sum(); - var translationsPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow; + _translationsQueuedPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow; - if( translationsPerSecond <= Settings.MaxTranslationsQueuedPerSecond ) + if( _translationsQueuedPerSecond <= Settings.MaxTranslationsQueuedPerSecond ) { _timeExceededThreshold = null; } } - private void AddTranslation( TranslationKeys key, string value ) + private void AddTranslation( string key, string value ) { - _translations[ key.OriginalKey ] = value; - _translatedTexts.Add( value ); + _translations[ key ] = value; + _reverseTranslations[ value ] = key; + } - if( Settings.IgnoreWhitespaceInDialogue && key.IsDialogue ) - { - _translations[ key.DialogueKey ] = value; - } + private void AddTranslation( TranslationKey key, string value ) + { + _translations[ key.GetDictionaryLookupKey() ] = value; + _reverseTranslations[ value ] = key.GetDictionaryLookupKey(); } - private void QueueNewUntranslatedForClipboard( TranslationKeys key ) + private void QueueNewUntranslatedForClipboard( TranslationKey key ) { - if( Settings.CopyToClipboard ) + if( Settings.CopyToClipboard && Features.SupportsClipboard ) { - if( !_textsToCopyToClipboard.Contains( key.ForcedRelevantKey ) ) + if( !_textsToCopyToClipboard.Contains( key.RelevantText ) ) { - _textsToCopyToClipboard.Add( key.ForcedRelevantKey ); - _textsToCopyToClipboardOrdered.Add( key.ForcedRelevantKey ); + _textsToCopyToClipboard.Add( key.RelevantText ); + _textsToCopyToClipboardOrdered.Add( key.RelevantText ); _clipboardUpdated = Time.realtimeSinceStartup; } } } - private void QueueNewUntranslatedForDisk( TranslationKeys key ) + private void QueueNewUntranslatedForDisk( TranslationKey key ) { - _newUntranslated.Add( key.RelevantKey ); + _newUntranslated.Add( key.GetDictionaryLookupKey() ); } - private void QueueNewTranslationForDisk( TranslationKeys key, string value ) + private void QueueNewTranslationForDisk( TranslationKey key, string value ) { lock( _writeToFileSync ) { - _newTranslations[ key.RelevantKey ] = value; + _newTranslations[ key.GetDictionaryLookupKey() ] = value; } } - private bool TryGetTranslation( TranslationKeys key, out string value ) + private void QueueNewTranslationForDisk( string key, string value ) { - return _translations.TryGetValue( key.OriginalKey, out value ) || ( Settings.IgnoreWhitespaceInDialogue && _translations.TryGetValue( key.DialogueKey, out value ) ); + lock( _writeToFileSync ) + { + _newTranslations[ key ] = value; + } + } + + private bool TryGetTranslation( TranslationKey key, out string value ) + { + var lookup = key.GetDictionaryLookupKey(); + var result = _translations.TryGetValue( lookup, out value ); + if( result ) + { + return result; + } + else if( _staticTranslations.Count > 0 ) + { + if( _staticTranslations.TryGetValue( lookup, out value ) ) + { + QueueNewTranslationForDisk( lookup, value ); + AddTranslation( lookup, value ); + return true; + } + } + return result; + } + + public bool TryGetReverseTranslation( string value, out string key ) + { + return _reverseTranslations.TryGetValue( value, out key ); } - private string Override_TextChanged( object ui, string text ) + public string Hook_TextChanged_WithResult( object ui, string text ) { - if( _hooksEnabled && !Settings.IsShutdown ) + if( !ui.IsKnownType() ) return null; + + if( _hooksEnabled ) { return TranslateOrQueueWebJob( ui, text, true ); } @@ -345,7 +644,7 @@ private string Override_TextChanged( object ui, string text ) public void Hook_TextChanged( object ui ) { - if( _hooksEnabled && !Settings.IsShutdown ) + if( _hooksEnabled ) { TranslateOrQueueWebJob( ui, null, false ); } @@ -353,19 +652,19 @@ public void Hook_TextChanged( object ui ) public void Hook_TextInitialized( object ui ) { - if( _hooksEnabled && !Settings.IsShutdown ) + if( _hooksEnabled ) { TranslateOrQueueWebJob( ui, null, true ); } } - private void SetTranslatedText( object ui, string text, TranslationInfo info ) + private void SetTranslatedText( object ui, string translatedText, TranslationInfo info ) { - info?.SetTranslatedText( text ); + info?.SetTranslatedText( translatedText ); if( _isInTranslatedMode ) { - SetText( ui, text, true, info ); + SetText( ui, translatedText, true, info ); } } @@ -387,20 +686,44 @@ private void SetText( object ui, string text, bool isTranslated, TranslationInfo info.IsCurrentlySettingText = true; } - ui.SetText( text ); - - if( isTranslated ) + if( _changeFont ) { - info?.ResizeUI( ui ); + if( isTranslated ) + { + info?.ChangeFont( ui ); + } + else + { + info?.UnchangeFont( ui ); + } } - else + + if( Settings.EnableUIResizing ) { - info?.UnresizeUI( ui ); + if( isTranslated ) + { + info?.ResizeUI( ui ); + } + else + { + info?.UnresizeUI( ui ); + } } + + // NGUI only behaves if you set the text after the resize behaviour + ui.SetText( text ); + } + catch( TargetInvocationException ) + { + // might happen with NGUI + } + catch( NullReferenceException ) + { + // This is likely happened due to a scene change. } catch( Exception e ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error occurred while setting text on a component." + Environment.NewLine + e ); + Logger.Current.Error( e, "An error occurred while setting text on a component." ); } finally { @@ -419,7 +742,12 @@ private void SetText( object ui, string text, bool isTranslated, TranslationInfo /// private bool IsTranslatable( string str ) { - return _symbolCheck( str ) && str.Length <= Settings.MaxCharactersPerTranslation && !_translatedTexts.Contains( str ); + return _symbolCheck( str ) && str.Length <= Settings.MaxCharactersPerTranslation && !_reverseTranslations.ContainsKey( str ); + } + + private bool IsShortText( string str ) + { + return str.Length <= ( Settings.MaxCharactersPerTranslation / 2 ); } public bool ShouldTranslate( object ui ) @@ -450,22 +778,23 @@ private string TranslateOrQueueWebJob( object ui, string text, bool isAwakening { return null; } + if( _ongoingOperations.Contains( ui ) ) { - return null; + return TranslateImmediate( ui, text, info ); } - - if( Settings.Delay == 0 || !SupportsStabilization( ui ) ) + var supportsStabilization = ui.SupportsStabilization(); + if( Settings.Delay == 0 || !supportsStabilization ) { - return TranslateOrQueueWebJobImmediate( ui, text, info ); + return TranslateOrQueueWebJobImmediate( ui, text, info, supportsStabilization ); } else { StartCoroutine( DelayForSeconds( Settings.Delay, () => { - TranslateOrQueueWebJobImmediate( ui, text, info ); + TranslateOrQueueWebJobImmediate( ui, text, info, supportsStabilization ); } ) ); } @@ -479,21 +808,48 @@ public static bool IsCurrentlySetting( TranslationInfo info ) return info.IsCurrentlySettingText; } + private string TranslateImmediate( object ui, string text, TranslationInfo info ) + { + // Get the trimmed text + text = ( text ?? ui.GetText() ).TrimIfConfigured(); + + if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslate( ui ) && !IsCurrentlySetting( info ) ) + { + info?.Reset( text ); + + var textKey = new TranslationKey( ui, text, ui.IsSpammingComponent(), false ); + + // if we already have translation loaded in our _translatios dictionary, simply load it and set text + string translation; + if( TryGetTranslation( textKey, out translation ) ) + { + if( !string.IsNullOrEmpty( translation ) ) + { + SetTranslatedText( ui, textKey.Untemplate( translation ), info ); + return translation; + } + } + } + + return null; + } + /// /// Translates the string of a UI text or queues it up to be translated /// by the HTTP translation service. /// - private string TranslateOrQueueWebJobImmediate( object ui, string text, TranslationInfo info ) + private string TranslateOrQueueWebJobImmediate( object ui, string text, TranslationInfo info, bool supportsStabilization, TranslationContext context = null ) { // Get the trimmed text - text = ( text ?? ui.GetText() ).Trim(); + text = ( text ?? ui.GetText() ).TrimIfConfigured(); // Ensure that we actually want to translate this text and its owning UI element. if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslate( ui ) && !IsCurrentlySetting( info ) ) { info?.Reset( text ); + var isSpammer = ui.IsSpammingComponent(); + var textKey = new TranslationKey( ui, text, isSpammer, context != null ); - var textKey = new TranslationKeys( text ); // if we already have translation loaded in our _translatios dictionary, simply load it and set text string translation; @@ -503,13 +859,31 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat if( !string.IsNullOrEmpty( translation ) ) { - SetTranslatedText( ui, translation, info ); + SetTranslatedText( ui, textKey.Untemplate( translation ), info ); return translation; } } else { - if( SupportsStabilization( ui ) ) + if( context == null && ui.SupportsRichText() ) + { + var parser = UnityTextParsers.GetTextParserByGameEngine(); + if( parser != null ) + { + var result = parser.Parse( text ); + if( result.HasRichSyntax ) + { + translation = TranslateOrQueueWebJobImmediateByParserResult( ui, result, true ); + if( translation != null ) + { + SetTranslatedText( ui, translation, info ); // get rid of textKey here!! + } + return translation; + } + } + } + + if( supportsStabilization && context == null ) // never stabilize a text that is contextualized or that does not support stabilization { // if we dont know what text to translate it to, we need to figure it out. // this might take a while, so add the UI text component to the ongoing operations @@ -528,8 +902,8 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat StartCoroutine( WaitForTextStablization( ui: ui, - delay: 0.5f, - maxTries: 100, // 100 tries == 50 seconds + delay: 1.0f, // 1 second to prevent '1 second tickers' from getting translated + maxTries: 60, // 50 tries, about 1 minute currentTries: 0, onMaxTriesExceeded: () => { @@ -541,7 +915,7 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat if( !string.IsNullOrEmpty( stabilizedText ) && IsTranslatable( stabilizedText ) ) { - var stabilizedTextKey = new TranslationKeys( stabilizedText ); + var stabilizedTextKey = new TranslationKey( ui, stabilizedText, false ); QueueNewUntranslatedForClipboard( stabilizedTextKey ); @@ -552,17 +926,37 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat { if( !string.IsNullOrEmpty( translation ) ) { + // stabilized, no need to untemplate SetTranslatedText( ui, translation, info ); } } else { + if( context == null && ui.SupportsRichText() ) + { + var parser = UnityTextParsers.GetTextParserByGameEngine(); + if( parser != null ) + { + var result = parser.Parse( stabilizedText ); + if( result.HasRichSyntax ) + { + var translatedText = TranslateOrQueueWebJobImmediateByParserResult( ui, result, true ); + if( translatedText != null ) + { + // stabilized, no need to untemplate + SetTranslatedText( ui, translatedText, info ); + } + return; + } + } + } + // Lets try not to spam a service that might not be there... - if( AutoTranslateClient.IsConfigured ) + if( _endpoint != null ) { - if( _consecutiveErrors < Settings.MaxErrors ) + if( !Settings.IsShutdown ) { - var job = GetOrCreateTranslationJobFor( stabilizedTextKey ); + var job = GetOrCreateTranslationJobFor( ui, stabilizedTextKey, context ); job.Components.Add( ui ); } } @@ -580,27 +974,20 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat _ongoingOperations.Remove( ui ); } } - else + else if( !isSpammer || ( isSpammer && IsShortText( text ) ) ) { - if( !_startedOperationsForNonStabilizableComponents.Contains( text ) && !text.ContainsNumbers() ) + // Lets try not to spam a service that might not be there... + if( _endpoint != null ) { - _startedOperationsForNonStabilizableComponents.Add( text ); - - QueueNewUntranslatedForClipboard( textKey ); - - // Lets try not to spam a service that might not be there... - if( AutoTranslateClient.IsConfigured ) + if( !Settings.IsShutdown ) { - if( _consecutiveErrors < Settings.MaxErrors ) - { - GetOrCreateTranslationJobFor( textKey ); - } - } - else - { - QueueNewUntranslatedForDisk( textKey ); + var job = GetOrCreateTranslationJobFor( ui, textKey, context ); } } + else + { + QueueNewUntranslatedForDisk( textKey ); + } } } } @@ -608,9 +995,45 @@ private string TranslateOrQueueWebJobImmediate( object ui, string text, Translat return null; } - public bool SupportsStabilization( object ui ) + private string TranslateOrQueueWebJobImmediateByParserResult( object ui, ParserResult result, bool allowStartJob ) { - return !( ui is GUIContent ); + Dictionary translations = new Dictionary(); + + // attempt to lookup ALL strings immediately; return result if possible; queue operations + foreach( var kvp in result.Arguments ) + { + var key = kvp.Key; + var value = kvp.Value.TrimIfConfigured(); + if( !string.IsNullOrEmpty( value ) && IsTranslatable( value ) ) + { + var valueKey = new TranslationKey( ui, value, false, true ); + string partTranslation; + if( TryGetTranslation( valueKey, out partTranslation ) ) + { + translations.Add( key, partTranslation ); + } + else if( allowStartJob ) + { + // incomplete, must start job + var context = new TranslationContext( ui, result ); + TranslateOrQueueWebJobImmediate( null, value, null, false, context ); + } + } + else + { + // the value will do + translations.Add( key, value ); + } + } + + if( result.Arguments.Count == translations.Count ) + { + return result.Untemplate( translations ); + } + else + { + return null; // could not perform complete translation + } } /// @@ -620,7 +1043,10 @@ public bool SupportsStabilization( object ui ) /// public IEnumerator WaitForTextStablization( object ui, float delay, int maxTries, int currentTries, Action onTextStabilized, Action onMaxTriesExceeded ) { - if( currentTries < maxTries ) // shortcircuit + yield return 0; // wait a single frame to allow any external plugins to complete their hooking logic + + bool succeeded = false; + while( currentTries < maxTries ) // shortcircuit { var beforeText = ui.GetText(); yield return new WaitForSeconds( delay ); @@ -628,14 +1054,15 @@ public IEnumerator WaitForTextStablization( object ui, float delay, int maxTries if( beforeText == afterText ) { - onTextStabilized( afterText.Trim() ); - } - else - { - StartCoroutine( WaitForTextStablization( ui, delay, maxTries, currentTries + 1, onTextStabilized, onMaxTriesExceeded ) ); + onTextStabilized( afterText.TrimIfConfigured() ); + succeeded = true; + break; } + + currentTries++; } - else + + if( !succeeded ) { onMaxTriesExceeded(); } @@ -648,17 +1075,43 @@ public IEnumerator DelayForSeconds( float delay, Action onContinue ) onContinue(); } - public void Update() + public void Start() { - if( Settings.IsShutdown ) return; + if( !_initialized ) + { + _initialized = true; + Initialize(); + } + } + public void Update() + { try { - CopyToClipboard(); - ResetThresholdTimerIfRequired(); + if( _endpoint != null ) + { + _endpoint.OnUpdate(); + } - KickoffTranslations(); - FinishTranslations(); + if( Features.SupportsClipboard ) + { + CopyToClipboard(); + } + + if( !Settings.IsShutdown ) + { + PeriodicResetFrameCheck(); + IncrementBatchOperations(); + ResetThresholdTimerIfRequired(); + KickoffTranslations(); + FinishTranslations(); + + if( _nextAdvUpdate.HasValue && Time.time > _nextAdvUpdate ) + { + _nextAdvUpdate = null; + UpdateUtageText(); + } + } if( Input.anyKey ) { @@ -682,7 +1135,7 @@ public void Update() } catch( Exception e ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error occurred in Update callback. " + Environment.NewLine + e ); + Logger.Current.Error( e, "An error occurred in Update callback. " ); } } @@ -691,54 +1144,202 @@ public void Update() private void KickoffTranslations() { - foreach( var kvp in _unstartedJobs ) + if( _endpoint == null ) return; + + if( Settings.EnableBatching && _endpoint.SupportsLineSplitting && !_batchLogicHasFailed && _unstartedJobs.Count > 1 && _availableBatchOperations > 0 ) { - if( !AutoTranslateClient.HasAvailableClients ) break; + while( _unstartedJobs.Count > 0 && _availableBatchOperations > 0 ) + { + if( _endpoint.IsBusy ) break; - var key = kvp.Key; - var job = kvp.Value; - _kickedOff.Add( key ); + var kvps = _unstartedJobs.Take( Settings.BatchSize ).ToList(); + var batch = new TranslationBatch(); + + foreach( var kvp in kvps ) + { + var key = kvp.Key; + var job = kvp.Value; + _kickedOff.Add( key ); - // lets see if the text should still be translated before kicking anything off - if( !job.AnyComponentsStillHasOriginalUntranslatedText() ) continue; + if( !job.AnyComponentsStillHasOriginalUntranslatedTextOrContextual() ) continue; - StartCoroutine( AutoTranslateClient.TranslateByWWW( job.Keys.ForcedRelevantKey, Settings.FromLanguage, Settings.Language, translatedText => - { - _consecutiveErrors = 0; + batch.Add( job ); + _ongoingJobs[ key ] = job; + } - if( Settings.ForceSplitTextAfterCharacters > 0 ) + if( !batch.IsEmpty ) { - translatedText = translatedText.SplitToLines( Settings.ForceSplitTextAfterCharacters, '\n', ' ', ' ' ); + _availableBatchOperations--; + + StartCoroutine( _endpoint.Translate( batch.GetFullTranslationKey(), Settings.FromLanguage, Settings.Language, translatedText => OnBatchTranslationCompleted( batch, translatedText ), + () => OnTranslationFailed( batch ) ) ); } + } + } + else + { + foreach( var kvp in _unstartedJobs ) + { + if( _endpoint.IsBusy ) break; + + var key = kvp.Key; + var job = kvp.Value; + _kickedOff.Add( key ); + + // lets see if the text should still be translated before kicking anything off + if( !job.AnyComponentsStillHasOriginalUntranslatedTextOrContextual() ) continue; + + _ongoingJobs[ key ] = job; + + StartCoroutine( _endpoint.Translate( job.Key.GetDictionaryLookupKey(), Settings.FromLanguage, Settings.Language, translatedText => OnSingleTranslationCompleted( job, translatedText ), + () => OnTranslationFailed( job ) ) ); + } + } + for( int i = 0 ; i < _kickedOff.Count ; i++ ) + { + _unstartedJobs.Remove( _kickedOff[ i ] ); + } - job.TranslatedText = translatedText; + _kickedOff.Clear(); + } + public void OnBatchTranslationCompleted( TranslationBatch batch, string translatedTextBatch ) + { + if( !Settings.IsShutdown ) + { + if( Settings.TranslationCount > Settings.MaxTranslationsBeforeShutdown ) + { + Settings.IsShutdown = true; + Logger.Current.Error( $"Maximum translations ({Settings.MaxTranslationsBeforeShutdown}) per session reached. Shutting plugin down." ); + } + } + + _consecutiveErrors = 0; + + var succeeded = batch.MatchWithTranslations( translatedTextBatch ); + if( succeeded ) + { + foreach( var tracker in batch.Trackers ) + { + Settings.TranslationCount++; + + var job = tracker.Job; + var translatedText = tracker.RawTranslatedText; if( !string.IsNullOrEmpty( translatedText ) ) { - QueueNewTranslationForDisk( job.Keys, translatedText ); + if( Settings.ForceSplitTextAfterCharacters > 0 ) + { + translatedText = translatedText.SplitToLines( Settings.ForceSplitTextAfterCharacters, '\n', ' ', ' ' ); + } + job.TranslatedText = job.Key.RepairTemplate( translatedText ); + QueueNewTranslationForDisk( job.Key, translatedText ); _completedJobs.Add( job ); } - }, - () => + + AddTranslation( job.Key, job.TranslatedText ); + job.State = TranslationJobState.Succeeded; + _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() ); + } + } + else + { + // might as well re-add all translation jobs, and never do this again! + _batchLogicHasFailed = true; + foreach( var tracker in batch.Trackers ) { - _consecutiveErrors++; + Settings.TranslationCount++; - if( _consecutiveErrors > Settings.MaxErrors && !Settings.IsShutdown ) + var key = tracker.Job.Key.GetDictionaryLookupKey(); + if( !_unstartedJobs.ContainsKey( key ) ) { - Settings.IsShutdown = true; - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: More than 5 consecutive errors occurred. Shutting down plugin..." ); + _unstartedJobs[ key ] = tracker.Job; } - } ) ); + _ongoingJobs.Remove( key ); + } + + Logger.Current.Error( "A batch operation failed. Disabling batching and restarting failed jobs." ); } + } - for( int i = 0 ; i < _kickedOff.Count ; i++ ) + private void OnSingleTranslationCompleted( TranslationJob job, string translatedText ) + { + Settings.TranslationCount++; + + if( !Settings.IsShutdown ) { - _unstartedJobs.Remove( _kickedOff[ i ] ); + if( Settings.TranslationCount > Settings.MaxTranslationsBeforeShutdown ) + { + Settings.IsShutdown = true; + Logger.Current.Error( $"Maximum translations ({Settings.MaxTranslationsBeforeShutdown}) per session reached. Shutting plugin down." ); + } } - _kickedOff.Clear(); + _consecutiveErrors = 0; + + if( !string.IsNullOrEmpty( translatedText ) ) + { + if( Settings.ForceSplitTextAfterCharacters > 0 ) + { + translatedText = translatedText.SplitToLines( Settings.ForceSplitTextAfterCharacters, '\n', ' ', ' ' ); + } + job.TranslatedText = job.Key.RepairTemplate( translatedText ); + + QueueNewTranslationForDisk( job.Key, translatedText ); + _completedJobs.Add( job ); + } + + AddTranslation( job.Key, job.TranslatedText ); + job.State = TranslationJobState.Succeeded; + _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() ); + } + + private void OnTranslationFailed( TranslationJob job ) + { + Settings.TranslationCount++; // counts as a translation + _consecutiveErrors++; + + job.State = TranslationJobState.Failed; + _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() ); + + if( !Settings.IsShutdown ) + { + if( _consecutiveErrors >= Settings.MaxErrors ) + { + Settings.IsShutdown = true; + Logger.Current.Error( $"{Settings.MaxErrors} or more consecutive errors occurred. Shutting down plugin." ); + + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + } + } + } + + private void OnTranslationFailed( TranslationBatch batch ) + { + Settings.TranslationCount++; // counts as a translation + _consecutiveErrors++; + + foreach( var tracker in batch.Trackers ) + { + tracker.Job.State = TranslationJobState.Failed; + _ongoingJobs.Remove( tracker.Job.Key.GetDictionaryLookupKey() ); + } + + if( !Settings.IsShutdown ) + { + if( _consecutiveErrors >= Settings.MaxErrors ) + { + Settings.IsShutdown = true; + Logger.Current.Error( $"{Settings.MaxErrors} or more consecutive errors occurred. Shutting down plugin." ); + + _unstartedJobs.Clear(); + _completedJobs.Clear(); + _ongoingJobs.Clear(); + } + } } private void FinishTranslations() @@ -753,19 +1354,84 @@ private void FinishTranslations() foreach( var component in job.Components ) { // update the original text, but only if it has not been chaanged already for some reason (could be other translator plugin or game itself) - var text = component.GetText().Trim(); - if( text == job.Keys.OriginalKey ) + try + { + var text = component.GetText().TrimIfConfigured(); + if( text == job.Key.OriginalText ) + { + var info = component.GetTranslationInfo( false ); + SetTranslatedText( component, job.TranslatedText, info ); + } + } + catch( NullReferenceException ) { - var info = component.GetTranslationInfo( false ); - SetTranslatedText( component, job.TranslatedText, info ); + // might fail if compoent is no longer associated to game + } + } + + // handle each context + foreach( var context in job.Contexts ) + { + // are all jobs within this context completed? If so, we can set the text + if( context.Jobs.All( x => x.State == TranslationJobState.Succeeded ) ) + { + try + { + + var text = context.Component.GetText().TrimIfConfigured(); + var result = context.Result; + Dictionary translations = new Dictionary(); + var translatedText = TranslateOrQueueWebJobImmediateByParserResult( null, result, false ); + + if( !string.IsNullOrEmpty( translatedText ) ) + { + if( !_translations.ContainsKey( context.Result.OriginalText ) ) + { + AddTranslation( context.Result.OriginalText, translatedText ); + QueueNewTranslationForDisk( context.Result.OriginalText, translatedText ); + } + + if( text == result.OriginalText ) + { + if( translatedText != null ) + { + var info = context.Component.GetTranslationInfo( false ); + SetTranslatedText( context.Component, translatedText, info ); + } + } + } + } + catch( NullReferenceException ) + { + + } } } - AddTranslation( job.Keys, job.TranslatedText ); + + // Utage support + if( Constants.Types.AdvEngine != null + && job.OriginalSources.Any( x => Constants.Types.AdvCommand.IsAssignableFrom( x.GetType() ) ) ) + { + _nextAdvUpdate = Time.time + 0.5f; + } } } } + private void UpdateUtageText() + { + if( _advEngine == null ) + { + _advEngine = GameObject.FindObjectOfType( Constants.Types.AdvEngine ); + } + + if( _advEngine != null ) + { + AccessTools.Method( Constants.Types.AdvEngine, "ChangeLanguage" )?.Invoke( _advEngine, new object[ 0 ] ); + } + } + private void ReloadTranslations() { LoadTranslations(); @@ -775,10 +1441,10 @@ private void ReloadTranslations() var info = kvp.Value as TranslationInfo; if( info != null && !string.IsNullOrEmpty( info.OriginalText ) ) { - var key = new TranslationKeys( info.OriginalText ); + var key = new TranslationKey( kvp.Key, info.OriginalText, false ); if( TryGetTranslation( key, out string translatedText ) && !string.IsNullOrEmpty( translatedText ) ) { - SetTranslatedText( kvp.Key, translatedText, info ); + SetTranslatedText( kvp.Key, translatedText, info ); // no need to untemplatize the translated text } } } @@ -819,11 +1485,14 @@ private void DumpUntranslated() private void ToggleTranslation() { _isInTranslatedMode = !_isInTranslatedMode; + var objects = ObjectExtensions.GetAllRegisteredObjects(); + + Logger.Current.Info( $"Toggling translations of {objects.Count} objects." ); if( _isInTranslatedMode ) { // make sure we use the translated version of all texts - foreach( var kvp in ObjectExtensions.GetAllRegisteredObjects() ) + foreach( var kvp in objects ) { var ui = kvp.Key; try @@ -848,7 +1517,7 @@ private void ToggleTranslation() else { // make sure we use the original version of all texts - foreach( var kvp in ObjectExtensions.GetAllRegisteredObjects() ) + foreach( var kvp in objects ) { var ui = kvp.Key; try @@ -896,7 +1565,7 @@ private void CopyToClipboard() } catch( Exception e ) { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error while copying text to clipboard. " + Environment.NewLine + e ); + Logger.Current.Error( e, "An error while copying text to clipboard." ); } finally { @@ -926,7 +1595,7 @@ private IEnumerable GetAllRoots() var objects = GameObject.FindObjectsOfType(); foreach( var obj in objects ) { - if( obj.transform.parent == null ) + if( obj.transform != null && obj.transform.parent == null ) { yield return obj; } @@ -935,18 +1604,24 @@ private IEnumerable GetAllRoots() private void TraverseChildren( StreamWriter writer, GameObject obj, string identation ) { - var layer = LayerMask.LayerToName( obj.gameObject.layer ); - var components = string.Join( ", ", obj.GetComponents().Select( x => x.GetType().Name ).ToArray() ); - var line = string.Format( "{0,-50} {1,100}", - identation + obj.gameObject.name + " [" + layer + "]", - components ); + if( obj != null ) + { + var layer = LayerMask.LayerToName( obj.layer ); + var components = string.Join( ", ", obj.GetComponents().Select( x => x?.GetType()?.Name ).Where( x => x != null ).ToArray() ); + var line = string.Format( "{0,-50} {1,100}", + identation + obj.name + " [" + layer + "]", + components ); - writer.WriteLine( line ); + writer.WriteLine( line ); - for( int i = 0 ; i < obj.transform.childCount ; i++ ) - { - var child = obj.transform.GetChild( i ); - TraverseChildren( writer, child.gameObject, identation + " " ); + if( obj.transform != null ) + { + for( int i = 0 ; i < obj.transform.childCount ; i++ ) + { + var child = obj.transform.GetChild( i ); + TraverseChildren( writer, child.gameObject, identation + " " ); + } + } } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationBatch.cs b/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationBatch.cs new file mode 100644 index 00000000..1e3487a3 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationBatch.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core.Batching +{ + public class TranslationBatch + { + public TranslationBatch() + { + Trackers = new List(); + } + + public List Trackers { get; private set; } + + public bool IsEmpty => Trackers.Count == 0; + + public int TotalLinesCount { get; set; } + + public void Add( TranslationJob job ) + { + var lines = new TranslationLineTracker( job ); + Trackers.Add( lines ); + TotalLinesCount += lines.LinesCount; + } + + public bool MatchWithTranslations( string allTranslations ) + { + var lines = allTranslations.Split( '\n' ); + + if( lines.Length != TotalLinesCount ) return false; + + int current = 0; + foreach( var tracker in Trackers ) + { + var builder = new StringBuilder( 32 ); + for( int i = 0 ; i < tracker.LinesCount ; i++ ) + { + var translation = lines[ current++ ]; + builder.Append( translation ); + + // ADD NEW LINE IF NEEDED + if( !( i == tracker.LinesCount - 1 ) ) // if not last line + { + builder.Append( '\n' ); + } + } + var fullTranslation = builder.ToString(); + + tracker.RawTranslatedText = fullTranslation; + } + + return true; + } + + public string GetFullTranslationKey() + { + var builder = new StringBuilder(); + for( int i = 0 ; i < Trackers.Count ; i++ ) + { + var tracker = Trackers[ i ]; + builder.Append( tracker.Job.Key.GetDictionaryLookupKey() ); + + if( !( i == Trackers.Count - 1 ) ) + { + builder.Append( '\n' ); + } + } + return builder.ToString(); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationLineTracker.cs b/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationLineTracker.cs new file mode 100644 index 00000000..871b5375 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationLineTracker.cs @@ -0,0 +1,19 @@ +using System.Linq; + +namespace XUnity.AutoTranslator.Plugin.Core.Batching +{ + public class TranslationLineTracker + { + public TranslationLineTracker( TranslationJob job ) + { + Job = job; + LinesCount = job.Key.GetDictionaryLookupKey().Count( c => c == '\n' ) + 1; + } + + public string RawTranslatedText { get; set; } + + public TranslationJob Job { get; private set; } + + public int LinesCount { get; private set; } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Configuration/IniKeyExtensions.cs b/src/XUnity.AutoTranslator.Plugin.Core/Configuration/IniKeyExtensions.cs index bfea2f21..119d58f0 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Configuration/IniKeyExtensions.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Configuration/IniKeyExtensions.cs @@ -16,12 +16,26 @@ public static T GetOrDefault( this IniKey that, T defaultValue, bool allowEmp var value = that.Value; if( string.IsNullOrEmpty( value ) ) { - that.Value = Convert.ToString( defaultValue, CultureInfo.InvariantCulture ); + if( typeof( T ).IsEnum ) + { + that.Value = Enum.GetName( typeof( T ), defaultValue ); + } + else + { + that.Value = Convert.ToString( defaultValue, CultureInfo.InvariantCulture ); + } return defaultValue; } else { - return (T)Convert.ChangeType( that.Value, typeof( T ), CultureInfo.InvariantCulture ); + if( typeof( T ).IsEnum ) + { + return (T)Enum.Parse( typeof( T ), that.Value, true ); + } + else + { + return (T)Convert.ChangeType( that.Value, typeof( T ), CultureInfo.InvariantCulture ); + } } } else @@ -29,12 +43,26 @@ public static T GetOrDefault( this IniKey that, T defaultValue, bool allowEmp var value = that.Value; if( value == null ) { - that.Value = Convert.ToString( defaultValue, CultureInfo.InvariantCulture ); + if( typeof( T ).IsEnum ) + { + that.Value = Enum.GetName( typeof( T ), defaultValue ); + } + else + { + that.Value = Convert.ToString( defaultValue, CultureInfo.InvariantCulture ); + } return defaultValue; } else { - return (T)Convert.ChangeType( that.Value, typeof( T ), CultureInfo.InvariantCulture ); + if( typeof( T ).IsEnum ) + { + return (T)Enum.Parse( typeof( T ), that.Value, true ); + } + else + { + return (T)Convert.ChangeType( that.Value, typeof( T ), CultureInfo.InvariantCulture ); + } } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs b/src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs index 79e3b48d..0487d4aa 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs @@ -4,26 +4,39 @@ using System.Linq; using System.Text; using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Debugging; +using XUnity.AutoTranslator.Plugin.Core.Utilities; namespace XUnity.AutoTranslator.Plugin.Core.Configuration { public static class Settings { // cannot be changed + public static readonly string DefaultLanguage = "en"; + public static readonly string DefaultFromLanguage = "ja"; + public static readonly string EnglishLanguage = "en"; public static readonly int MaxErrors = 5; public static readonly float ClipboardDebounceTime = 1f; - public static readonly int MaxTranslationsBeforeSlowdown = 1000; - public static readonly int MaxTranslationsBeforeShutdown = 6000; + public static readonly int MaxTranslationsBeforeShutdown = 8000; public static readonly int MaxUnstartedJobs = 3500; + public static readonly float IncreaseBatchOperationsEvery = 30; + public static readonly bool EnableObjectTracking = true; + public static readonly int MaximumStaggers = 6; + public static readonly int MaximumConsecutiveFramesTranslated = 90; + public static readonly int MaximumConsecutiveSecondsTranslated = 60; + public static bool UsesWhitespaceBetweenWords = false; + - public static int DefaultMaxConcurrentTranslations = 2; - public static int MaxConcurrentTranslations = DefaultMaxConcurrentTranslations; public static bool IsShutdown = false; + public static int TranslationCount = 0; + public static int MaxAvailableBatchOperations = 40; public static readonly float MaxTranslationsQueuedPerSecond = 5; public static readonly int MaxSecondsAboveTranslationThreshold = 30; - public static readonly int TranslationQueueWatchWindow = 10; - + public static readonly int TranslationQueueWatchWindow = 6; + + public static readonly int BatchSize = 10; + // can be changed public static string ServiceEndpoint; public static string Language; @@ -33,18 +46,35 @@ public static class Settings public static float Delay; public static int MaxCharactersPerTranslation; public static bool EnablePrintHierarchy; + public static bool EnableConsole; + public static bool EnableDebugLogs; public static string AutoTranslationsFilePath; public static bool EnableIMGUI; public static bool EnableUGUI; public static bool EnableNGUI; public static bool EnableTextMeshPro; + public static bool EnableUtage; public static bool AllowPluginHookOverride; public static bool IgnoreWhitespaceInDialogue; + public static bool IgnoreWhitespaceInNGUI; public static int MinDialogueChars; - public static bool EnableSSL; public static string BaiduAppId; public static string BaiduAppSecret; + public static string YandexAPIKey; + public static string WatsonAPIUrl; + public static string WatsonAPIUsername; + public static string WatsonAPIPassword; public static int ForceSplitTextAfterCharacters; + public static bool EnableMigrations; + public static string MigrationsTag; + public static bool EnableBatching; + public static bool TrimAllText; + public static bool EnableUIResizing; + public static string GoogleAPIKey; + public static bool UseStaticTranslations; + public static string OverrideFont; + public static string UserAgent; + public static WhitespaceHandlingStrategy WhitespaceRemovalStrategy; public static bool CopyToClipboard; public static int MaxClipboardCopyCharacters; @@ -61,19 +91,16 @@ public static void Configure() } Config.Current.Preferences.DeleteSection( "AutoTranslator" ); + Config.Current.Preferences[ "Service" ].DeleteKey( "EnableSSL" ); } - catch( Exception e ) - { - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: An error occurred while removing legacy configuration. " + Environment.NewLine + e ); - } + catch { } ServiceEndpoint = Config.Current.Preferences[ "Service" ][ "Endpoint" ].GetOrDefault( KnownEndpointNames.GoogleTranslate, true ); - EnableSSL = Config.Current.Preferences[ "Service" ][ "EnableSSL" ].GetOrDefault( false ); - Language = Config.Current.Preferences[ "General" ][ "Language" ].GetOrDefault( "en" ); - FromLanguage = Config.Current.Preferences[ "General" ][ "FromLanguage" ].GetOrDefault( "ja", true ); + Language = Config.Current.Preferences[ "General" ][ "Language" ].GetOrDefault( DefaultLanguage ); + FromLanguage = Config.Current.Preferences[ "General" ][ "FromLanguage" ].GetOrDefault( DefaultFromLanguage, true ); TranslationDirectory = Config.Current.Preferences[ "Files" ][ "Directory" ].GetOrDefault( @"Translation" ); OutputFile = Config.Current.Preferences[ "Files" ][ "OutputFile" ].GetOrDefault( @"Translation\_AutoGeneratedTranslations.{lang}.txt" ); @@ -82,24 +109,91 @@ public static void Configure() EnableUGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableUGUI" ].GetOrDefault( true ); EnableNGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableNGUI" ].GetOrDefault( true ); EnableTextMeshPro = Config.Current.Preferences[ "TextFrameworks" ][ "EnableTextMeshPro" ].GetOrDefault( true ); + EnableUtage = Config.Current.Preferences[ "TextFrameworks" ][ "EnableUtage" ].GetOrDefault( true ); AllowPluginHookOverride = Config.Current.Preferences[ "TextFrameworks" ][ "AllowPluginHookOverride" ].GetOrDefault( true ); Delay = Config.Current.Preferences[ "Behaviour" ][ "Delay" ].GetOrDefault( 0f ); - MaxCharactersPerTranslation = Config.Current.Preferences[ "Behaviour" ][ "MaxCharactersPerTranslation" ].GetOrDefault( 150 ); - IgnoreWhitespaceInDialogue = Config.Current.Preferences[ "Behaviour" ][ "IgnoreWhitespaceInDialogue" ].GetOrDefault( true ); + MaxCharactersPerTranslation = Config.Current.Preferences[ "Behaviour" ][ "MaxCharactersPerTranslation" ].GetOrDefault( 200 ); + IgnoreWhitespaceInDialogue = Config.Current.Preferences[ "Behaviour" ][ "IgnoreWhitespaceInDialogue" ].GetOrDefault( Types.AdvEngine == null ); + IgnoreWhitespaceInNGUI = Config.Current.Preferences[ "Behaviour" ][ "IgnoreWhitespaceInNGUI" ].GetOrDefault( true ); MinDialogueChars = Config.Current.Preferences[ "Behaviour" ][ "MinDialogueChars" ].GetOrDefault( 20 ); ForceSplitTextAfterCharacters = Config.Current.Preferences[ "Behaviour" ][ "ForceSplitTextAfterCharacters" ].GetOrDefault( 0 ); CopyToClipboard = Config.Current.Preferences[ "Behaviour" ][ "CopyToClipboard" ].GetOrDefault( false ); MaxClipboardCopyCharacters = Config.Current.Preferences[ "Behaviour" ][ "MaxClipboardCopyCharacters" ].GetOrDefault( 450 ); + EnableUIResizing = Config.Current.Preferences[ "Behaviour" ][ "EnableUIResizing" ].GetOrDefault( true ); + EnableBatching = Config.Current.Preferences[ "Behaviour" ][ "EnableBatching" ].GetOrDefault( true ); + TrimAllText = Config.Current.Preferences[ "Behaviour" ][ "TrimAllText" ].GetOrDefault( Types.AdvEngine == null ); + UseStaticTranslations = Config.Current.Preferences[ "Behaviour" ][ "UseStaticTranslations" ].GetOrDefault( true ); + OverrideFont = Config.Current.Preferences[ "Behaviour" ][ "OverrideFont" ].GetOrDefault( string.Empty ); + + // special handling because of enum parsing + try + { + WhitespaceRemovalStrategy = Config.Current.Preferences[ "Behaviour" ][ "WhitespaceRemovalStrategy" ].GetOrDefault( WhitespaceHandlingStrategy.TrimPerNewline ); + } + catch( Exception e ) + { + WhitespaceRemovalStrategy = WhitespaceHandlingStrategy.TrimPerNewline; + + Logger.Current.Warn( e, "An error occurred while configuring 'WhitespaceRemovalStrategy'. Using default." ); + } + + UserAgent = Config.Current.Preferences[ "Http" ][ "UserAgent" ].GetOrDefault( string.Empty ); + + GoogleAPIKey = Config.Current.Preferences[ "GoogleLegitimate" ][ "GoogleAPIKey" ].GetOrDefault( "" ); BaiduAppId = Config.Current.Preferences[ "Baidu" ][ "BaiduAppId" ].GetOrDefault( "" ); BaiduAppSecret = Config.Current.Preferences[ "Baidu" ][ "BaiduAppSecret" ].GetOrDefault( "" ); - + + YandexAPIKey = Config.Current.Preferences[ "Yandex" ][ "YandexAPIKey" ].GetOrDefault( "" ); + + WatsonAPIUrl = Config.Current.Preferences[ "Watson" ][ "WatsonAPIUrl" ].GetOrDefault( "" ); + WatsonAPIUsername = Config.Current.Preferences[ "Watson" ][ "WatsonAPIUsername" ].GetOrDefault( "" ); + WatsonAPIPassword = Config.Current.Preferences[ "Watson" ][ "WatsonAPIPassword" ].GetOrDefault( "" ); + EnablePrintHierarchy = Config.Current.Preferences[ "Debug" ][ "EnablePrintHierarchy" ].GetOrDefault( false ); + EnableConsole = Config.Current.Preferences[ "Debug" ][ "EnableConsole" ].GetOrDefault( false ); + EnableDebugLogs = Config.Current.Preferences[ "Debug" ][ "EnableLog" ].GetOrDefault( false ); + + EnableMigrations = Config.Current.Preferences[ "Migrations" ][ "Enable" ].GetOrDefault( true ); + MigrationsTag = Config.Current.Preferences[ "Migrations" ][ "Tag" ].GetOrDefault( string.Empty ); AutoTranslationsFilePath = Path.Combine( Config.Current.DataPath, OutputFile.Replace( "{lang}", Language ) ); + UsesWhitespaceBetweenWords = TextHelper.RequiresWhitespaceUponLineMerging( FromLanguage ); + + if( EnableMigrations ) + { + Migrate(); + } + + // update tag + MigrationsTag = Config.Current.Preferences[ "Migrations" ][ "Tag" ].Value = PluginData.Version; Config.Current.SaveConfig(); } + + private static void Migrate() + { + var currentTag = MigrationsTag; + var newTag = PluginData.Version; + + // migrate from unknown version to known version. Reset to google translate + if( string.IsNullOrEmpty( currentTag ) ) + { + if( ServiceEndpoint == KnownEndpointNames.GoogleTranslateHack ) + { + ServiceEndpoint = Config.Current.Preferences[ "Service" ][ "Endpoint" ].Value = KnownEndpointNames.GoogleTranslate; + } + } + } + + public static string GetUserAgent( string defaultUserAgent ) + { + if( !string.IsNullOrEmpty( UserAgent ) ) + { + return UserAgent; + } + return defaultUserAgent; + } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/ConsoleLogger.cs b/src/XUnity.AutoTranslator.Plugin.Core/ConsoleLogger.cs new file mode 100644 index 00000000..6535dad1 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/ConsoleLogger.cs @@ -0,0 +1,12 @@ +using System; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public class ConsoleLogger : Logger + { + protected override void Log( LogLevel level, string message ) + { + Console.WriteLine( $"{GetPrefix( level )} {message}" ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEndpointNames.cs b/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEndpointNames.cs index 1a140918..ed2afd9b 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEndpointNames.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEndpointNames.cs @@ -9,6 +9,16 @@ public static class KnownEndpointNames { public const string GoogleTranslate = "GoogleTranslate"; + public const string GoogleTranslateHack = "GoogleTranslateHack"; + + public const string GoogleTranslateLegitimate = "GoogleTranslateLegitimate"; + public const string BaiduTranslate = "BaiduTranslate"; + + public const string YandexTranslate = "YandexTranslate"; + + public const string WatsonTranslate = "WatsonTranslate"; + + public const string ExciteTranslate = "ExciteTranslate"; } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEvents.cs b/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEvents.cs index 435f31ef..28a97fa8 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEvents.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEvents.cs @@ -10,5 +10,6 @@ public static class KnownEvents public static string OnUnableToTranslateUGUI = "OnUnableToTranslateUGUI"; public static string OnUnableToTranslateTextMeshPro = "OnUnableToTranslateTextMeshPro"; public static string OnUnableToTranslateNGUI = "OnUnableToTranslateNGUI"; + public static string OnUnableToTranslateIMGUI = "OnUnableToTranslateIMGUI"; } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Constants/PluginData.cs b/src/XUnity.AutoTranslator.Plugin.Core/Constants/PluginData.cs index c87a1ca7..d0d24ad7 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Constants/PluginData.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Constants/PluginData.cs @@ -11,6 +11,6 @@ public static class PluginData public const string Name = "XUnity Auto Translator"; - public const string Version = "2.5.0"; + public const string Version = "2.14.0"; } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Constants/Types.cs b/src/XUnity.AutoTranslator.Plugin.Core/Constants/Types.cs index 85d3271e..44ab8159 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Constants/Types.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Constants/Types.cs @@ -6,6 +6,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Constants { public static class Types { + public static readonly Type TextEditor = FindType( "UnityEngine.TextEditor" ); + public static readonly Type CustomYieldInstruction = FindType( "UnityEngine.CustomYieldInstruction" ); + public static readonly Type TMP_InputField = FindType( "TMPro.TMP_InputField" ); public static readonly Type TMP_Text = FindType( "TMPro.TMP_Text" ); public static readonly Type TextMeshProUGUI = FindType( "TMPro.TextMeshProUGUI" ); @@ -18,6 +21,19 @@ public static class Types public static readonly Type UILabel = FindType( "UILabel" ); + public static readonly Type WWW = FindType( "UnityEngine.WWW" ); + + public static readonly Type UguiNovelText = FindType( "Utage.UguiNovelText" ); + + public static readonly Type AdvCommand = FindType( "Utage.AdvCommand" ); + + public static readonly Type AdvEngine = FindType( "Utage.AdvEngine" ); + + public static readonly Type AdvDataManager = FindType( "Utage.AdvDataManager" ); + + public static readonly Type AdvScenarioData = FindType( "Utage.AdvScenarioData" ); + + public static readonly Type AdvScenarioLabelData = FindType( "Utage.AdvScenarioLabelData" ); private static Type FindType( string name ) { diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Debugging/DebugConsole.cs b/src/XUnity.AutoTranslator.Plugin.Core/Debugging/DebugConsole.cs new file mode 100644 index 00000000..8fab2df6 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Debugging/DebugConsole.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core.Debugging +{ + public static class DebugConsole + { + private static IntPtr _consoleOut; + + public static void Enable() + { + var oldConsoleOut = Kernel32.GetStdHandle( -11 ); + if( !Kernel32.AllocConsole() ) return; + + _consoleOut = Kernel32.CreateFile( "CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero ); + if( !Kernel32.SetStdHandle( -11, _consoleOut ) ) return; + + Stream stream = Console.OpenStandardOutput(); + StreamWriter writer = new StreamWriter( stream, Encoding.Default ); + writer.AutoFlush = true; + + Console.SetOut( writer ); + Console.SetError( writer ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Debugging/Kernel32.cs b/src/XUnity.AutoTranslator.Plugin.Core/Debugging/Kernel32.cs new file mode 100644 index 00000000..4d244dd2 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Debugging/Kernel32.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core.Debugging +{ + public static class Kernel32 + { + [DllImport( "kernel32.dll", SetLastError = true )] + public static extern bool AllocConsole(); + + [DllImport( "kernel32.dll", SetLastError = false )] + public static extern bool FreeConsole(); + + [DllImport( "kernel32.dll", SetLastError = true )] + public static extern IntPtr GetStdHandle( int nStdHandle ); + + [DllImport( "kernel32.dll", SetLastError = true )] + public static extern bool SetStdHandle( int nStdHandle, IntPtr hConsoleOutput ); + + [DllImport( "kernel32.dll", CharSet = CharSet.Auto, SetLastError = true )] + public static extern IntPtr CreateFile( + string fileName, + int desiredAccess, + int shareMode, + IntPtr securityAttributes, + int creationDisposition, + int flagsAndAttributes, + IntPtr templateFile ); + + [DllImport( "kernel32.dll", ExactSpelling = true, SetLastError = true )] + public static extern bool CloseHandle( IntPtr handle ); + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ComponentExtensions.cs b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ComponentExtensions.cs index aa6a734b..ea275779 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ComponentExtensions.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ComponentExtensions.cs @@ -13,7 +13,10 @@ public static class ComponentExtensions public static string GetText( this object ui ) { + if( ui == null ) return null; + string text = null; + var type = ui.GetType(); if( ui is Text ) { @@ -34,6 +37,10 @@ public static string GetText( this object ui ) public static void SetText( this object ui, string text ) { + if( ui == null ) return; + + var type = ui.GetType(); + if( ui is Text ) { ( (Text)ui ).text = text; @@ -45,7 +52,6 @@ public static void SetText( this object ui, string text ) else { // fallback to reflective approach - var type = ui.GetType(); type.GetProperty( TextPropertyName )?.GetSetMethod()?.Invoke( ui, new[] { text } ); } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ObjectExtensions.cs b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ObjectExtensions.cs index 064eed9b..3f4ea6a1 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ObjectExtensions.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/ObjectExtensions.cs @@ -3,19 +3,77 @@ using System.Linq; using System.Text; using System.Threading; -using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using UnityEngine.UI; +using XUnity.AutoTranslator.Plugin.Core.Constants; using XUnity.AutoTranslator.Plugin.Core.Utilities; namespace XUnity.AutoTranslator.Plugin.Core.Extensions { public static class ObjectExtensions { + private static readonly string RichTextPropertyName = "richText"; + private static readonly object Sync = new object(); private static readonly WeakDictionary DynamicFields = new WeakDictionary(); + public static bool IsKnownType( this object ui ) + { + if( ui == null ) return false; + + var type = ui.GetType(); + + return ui is Text + || ui is UnityEngine.GUIContent + || ( Types.UILabel != null && Types.UILabel.IsAssignableFrom( type ) ) + || ( Types.TMP_Text != null && Types.TMP_Text.IsAssignableFrom( type ) ) + || ( Types.AdvCommand != null && Types.AdvCommand.IsAssignableFrom( type ) ); + } + + public static bool SupportsStabilization( this object ui ) + { + if( ui == null ) return false; + + var type = ui.GetType(); + + return ui is Text + || ( Types.UILabel != null && Types.UILabel.IsAssignableFrom( type ) ) + || ( Types.TMP_Text != null && Types.TMP_Text.IsAssignableFrom( type ) ); + } + + public static bool SupportsRichText( this object ui ) + { + if( ui == null ) return false; + + var type = ui.GetType(); + + return ( ui as Text )?.supportRichText == true + || ( Types.TMP_Text != null && Types.TMP_Text.IsAssignableFrom( type ) && Equals( type.GetProperty( RichTextPropertyName )?.GetValue( ui, null ), true ) ) + || ( Types.AdvCommand != null && Types.AdvCommand.IsAssignableFrom( type ) ) + || ( Types.UguiNovelText != null && Types.UguiNovelText.IsAssignableFrom( type ) ); + } + + public static bool IsSpammingComponent( this object ui ) + { + if( ui == null ) return false; + + return ui is UnityEngine.GUIContent; + } + + public static bool IsNGUI( this object ui ) + { + if( ui == null ) return false; + + var type = ui.GetType(); + + return Types.UILabel != null && Types.UILabel.IsAssignableFrom( type ); + } + public static TranslationInfo GetTranslationInfo( this object obj, bool isAwakening ) { - if( obj is GUIContent ) return null; + if( !Settings.EnableObjectTracking ) return null; + + if( !obj.SupportsStabilization() ) return null; var info = obj.Get(); @@ -50,7 +108,7 @@ public static void Cull() } } - public static IEnumerable> GetAllRegisteredObjects() + public static List> GetAllRegisteredObjects() { lock( Sync ) { diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs index a5ef9497..0b3130f1 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs @@ -33,16 +33,128 @@ public static class StringExtensions '9' }; - public static string ChangeToSingleLineForDialogue( this string that ) + private static readonly HashSet NumbersWithDot = new HashSet { - if( that.Length > Settings.MinDialogueChars ) // long strings often indicate dialog + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '.' + }; + + private static readonly char[] NewlinesCharacters = new char[] { '\r', '\n' }; + private static readonly char[] WhitespacesAndNewlines = new char[] { '\r', '\n', ' ', ' ' }; + + public static TemplatedString TemplatizeByNumbers( this string str ) + { + var dict = new Dictionary(); + bool isNumber = false; + StringBuilder carg = null; + char arg = 'A'; + + for( int i = 0 ; i < str.Length ; i++ ) + { + var c = str[ i ]; + if( isNumber ) + { + if( NumbersWithDot.Contains( c ) ) + { + carg.Append( c ); + } + else + { + // end current number + var variable = carg.ToString(); + var ok = true; + var c1 = variable[ 0 ]; + if( c1 == '.' ) + { + if( variable.Length == 1 ) + { + ok = false; + } + else + { + var c2 = variable[ 1 ]; + ok = Numbers.Contains( c2 ); + } + } + + if( ok && !dict.ContainsKey( variable ) ) + { + dict.Add( variable, "{{" + arg + "}}" ); + arg++; + } + + carg = null; + isNumber = false; + } + } + else + { + if( NumbersWithDot.Contains( c ) ) + { + isNumber = true; + carg = new StringBuilder(); + carg.Append( c ); + } + } + } + + if( carg != null ) + { + // end current number + var variable = carg.ToString(); + var ok = true; + var c1 = variable[ 0 ]; + if( c1 == '.' ) + { + if( variable.Length == 1 ) + { + ok = false; + } + else + { + var c2 = variable[ 1 ]; + ok = Numbers.Contains( c2 ); + } + } + + if( ok && !dict.ContainsKey( variable ) ) + { + dict.Add( variable, "{{" + arg + "}}" ); + arg++; + } + } + + if( dict.Count > 0 ) { - // Always change dialogue into one line. Otherwise translation services gets confused. - return that.RemoveWhitespace(); + foreach( var kvp in dict ) + { + str = str.Replace( kvp.Key, kvp.Value ); + } + + return new TemplatedString( str, dict.ToDictionary( x => x.Value, x => x.Key ) ); } else { - return that; + return null; } } @@ -73,10 +185,59 @@ public static string SplitToLines( this string text, int maxStringLength, params return sb.ToString(); } - public static string RemoveWhitespace( this string text ) + public static string TrimIfConfigured( this string text ) + { + if( text == null ) return text; + + if( Settings.TrimAllText ) + { + return text.Trim(); + } + return text; + } + + public static string RemoveWhitespaceAndNewlines( this string text ) { - // Japanese whitespace, wtf - return text.Replace( "\n", "" ).Replace( "\r", "" ).Replace( " ", "" ).Replace( " ", "" ); + var builder = new StringBuilder( text.Length ); + if( Settings.WhitespaceRemovalStrategy == WhitespaceHandlingStrategy.AllOccurrences ) + { + for( int i = 0 ; i < text.Length ; i++ ) + { + var c = text[ i ]; + switch( c ) + { + case '\n': + case '\r': + case ' ': + case ' ': + break; + default: + builder.Append( c ); + break; + } + } + } + else // if( Settings.WhitespaceHandlingStrategy == WhitespaceHandlingStrategy.TrimPerNewline ) + { + var lines = text.Split( NewlinesCharacters, StringSplitOptions.RemoveEmptyEntries ); + var lastLine = lines.Length - 1; + for( int i = 0 ; i < lines.Length ; i++ ) + { + var line = lines[ i ].Trim( WhitespacesAndNewlines ); + for( int j = 0 ; j < line.Length ; j++ ) + { + var c = line[ j ]; + builder.Append( c ); + } + + // do we need to add a space when merging lines? + if( Settings.UsesWhitespaceBetweenWords && i != lastLine ) // en, ru, ko? + { + builder.Append( ' ' ); + } + } + } + return builder.ToString(); } public static bool ContainsNumbers( this string text ) @@ -169,5 +330,68 @@ public static string UnescapeJson( this string str ) return builder.ToString(); } + + public static string EscapeJson( this string str ) + { + if( str == null || str.Length == 0 ) + { + return ""; + } + + char c; + int len = str.Length; + StringBuilder sb = new StringBuilder( len + 4 ); + for( int i = 0 ; i < len ; i += 1 ) + { + c = str[ i ]; + switch( c ) + { + case '\\': + case '"': + sb.Append( '\\' ); + sb.Append( c ); + break; + case '/': + sb.Append( '\\' ); + sb.Append( c ); + break; + case '\b': + sb.Append( "\\b" ); + break; + case '\t': + sb.Append( "\\t" ); + break; + case '\n': + sb.Append( "\\n" ); + break; + case '\f': + sb.Append( "\\f" ); + break; + case '\r': + sb.Append( "\\r" ); + break; + default: + sb.Append( c ); + break; + } + } + return sb.ToString(); + } + public static string GetBetween( this string strSource, string strStart, string strEnd ) + { + const int kNotFound = -1; + + var startIdx = strSource.IndexOf( strStart ); + if( startIdx != kNotFound ) + { + startIdx += strStart.Length; + var endIdx = strSource.IndexOf( strEnd, startIdx ); + if( endIdx > startIdx ) + { + return strSource.Substring( startIdx, endIdx - startIdx ); + } + } + return String.Empty; + } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Features.cs b/src/XUnity.AutoTranslator.Plugin.Core/Features.cs new file mode 100644 index 00000000..4bd1a1b5 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Features.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core.Constants; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public static class Features + { + public static readonly bool SupportsClipboard = false; + + public static readonly bool SupportsCustomYieldInstruction = false; + + static Features() + { + try + { + SupportsClipboard = Types.TextEditor?.GetProperty( "text" )?.GetSetMethod() != null; + } + catch( Exception ) + { + + } + + try + { + SupportsCustomYieldInstruction = Types.CustomYieldInstruction != null; + } + catch( Exception ) + { + + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Fonts/FontCache.cs b/src/XUnity.AutoTranslator.Plugin.Core/Fonts/FontCache.cs new file mode 100644 index 00000000..3082b28e --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Fonts/FontCache.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; + +namespace XUnity.AutoTranslator.Plugin.Core.Fonts +{ + public static class FontCache + { + private static readonly Dictionary CachedFonts = new Dictionary(); + + public static Font GetOrCreate( int size ) + { + if( !CachedFonts.TryGetValue( size, out Font font ) ) + { + font = Font.CreateDynamicFontFromOSFont( Settings.OverrideFont, size ); + GameObject.DontDestroyOnLoad( font ); + CachedFonts.Add( size, font ); + } + return font; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/HooksSetup.cs b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/HooksSetup.cs index d0956461..bd575fc0 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/HooksSetup.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/HooksSetup.cs @@ -19,48 +19,92 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks public static class HooksSetup { - public static void InstallHooks( Func defaultHook ) + public static void InstallHooks() { + var harmony = HarmonyInstance.Create( "gravydevsupreme.xunity.autotranslator" ); + + bool success = false; try { - var harmony = HarmonyInstance.Create( "gravydevsupreme.xunity.autotranslator" ); - - bool success = false; - if( Settings.EnableUGUI ) + if( Settings.EnableUGUI || Settings.EnableUtage ) { - success = SetupHook( KnownEvents.OnUnableToTranslateUGUI, defaultHook ); + success = SetupHook( KnownEvents.OnUnableToTranslateUGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult ); if( !success ) { harmony.PatchAll( UGUIHooks.All ); } } + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred while setting up hooks for UGUI." ); + } + try + { if( Settings.EnableTextMeshPro ) { - success = SetupHook( KnownEvents.OnUnableToTranslateTextMeshPro, defaultHook ); + success = SetupHook( KnownEvents.OnUnableToTranslateTextMeshPro, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult ); if( !success ) { harmony.PatchAll( TextMeshProHooks.All ); } } + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred while setting up hooks for TextMeshPro." ); + } + try + { if( Settings.EnableNGUI ) { - success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, defaultHook ); + success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult ); if( !success ) { harmony.PatchAll( NGUIHooks.All ); } } + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred while setting up hooks for NGUI." ); + } + try + { if( Settings.EnableIMGUI ) { - harmony.PatchAll( IMGUIHooks.All ); + success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult ); + if( !success ) + { + harmony.PatchAll( IMGUIHooks.All ); + + // This wont work in "newer" unity versions! + try + { + harmony.PatchType( typeof( DoButtonGridHook ) ); + } + catch { } + } + } + } + catch( Exception e ) + { + Logger.Current.Error( e, "An error occurred while setting up hooks for IMGUI." ); + } + + try + { + if( Settings.EnableUtage ) + { + harmony.PatchAll( UtageHooks.All ); } } catch( Exception e ) { - Console.WriteLine( "ERROR WHILE INITIALIZING AUTO TRANSLATOR: " + Environment.NewLine + e ); + Logger.Current.Error( e, "An error occurred while setting up hooks for Utage." ); } } @@ -95,6 +139,7 @@ public static bool SetupHook( string eventName, Func cal addMethod.Invoke( component, new object[] { callback } ); } + Logger.Current.Info( eventName + " was hooked by external plugin." ); return true; } catch { } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/IMGUIHooks.cs b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/IMGUIHooks.cs index d277f999..b7ee9a99 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/IMGUIHooks.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/IMGUIHooks.cs @@ -19,7 +19,6 @@ public static class IMGUIHooks typeof( DoButtonHook ), typeof( DoModalWindowHook ), typeof( DoWindowHook ), - typeof( DoButtonGridHook ), typeof( DoTextFieldHook ), typeof( DoToggleHook ), }; diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/NGUIHooks.cs b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/NGUIHooks.cs index f252114d..8d7692da 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/NGUIHooks.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/NGUIHooks.cs @@ -13,7 +13,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI public static class NGUIHooks { public static readonly Type[] All = new[] { - typeof( TextPropertyHook ) + typeof( TextPropertyHook ), + typeof( OnStartHook ) }; } @@ -32,7 +33,26 @@ static MethodBase TargetMethod( HarmonyInstance instance ) public static void Postfix( object __instance ) { - AutoTranslationPlugin.Current.Hook_TextChanged( __instance ); + AutoTranslationPlugin.Current.Hook_TextInitialized( __instance ); + } + } + + [Harmony, HarmonyAfter( Constants.KnownPlugins.DynamicTranslationLoader )] + public static class OnStartHook + { + static bool Prepare( HarmonyInstance instance ) + { + return Constants.Types.UILabel != null; + } + + static MethodBase TargetMethod( HarmonyInstance instance ) + { + return AccessTools.Method( Constants.Types.UILabel, "OnStart" ); + } + + public static void Postfix( object __instance ) + { + AutoTranslationPlugin.Current.Hook_TextInitialized( __instance ); } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Hooks/UtageHooks.cs b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/UtageHooks.cs new file mode 100644 index 00000000..4bdd96ab --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Hooks/UtageHooks.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using Harmony; +using XUnity.AutoTranslator.Plugin.Core.UtageSupport; + +namespace XUnity.AutoTranslator.Plugin.Core.Hooks +{ + public static class UtageHooks + { + public static readonly Type[] All = new[] { + typeof( AdvCommand_ParseCellLocalizedTextHook ), + typeof( AdvEngine_JumpScenario ), + }; + } + + [Harmony] + public static class AdvCommand_ParseCellLocalizedTextHook + { + static bool Prepare( HarmonyInstance instance ) + { + return Constants.Types.AdvCommand != null; + } + + static MethodBase TargetMethod( HarmonyInstance instance ) + { + return AccessTools.Method( Constants.Types.AdvCommand, "ParseCellLocalizedText", new Type[] { } ); + } + + static void Postfix( object __instance, ref string __result ) + { + var result = AutoTranslationPlugin.Current.Hook_TextChanged_WithResult( __instance, __result ); + if( !string.IsNullOrEmpty( result ) ) + { + __result = result; + } + } + } + + [Harmony] + public static class AdvEngine_JumpScenario + { + static bool Prepare( HarmonyInstance instance ) + { + return Constants.Types.AdvEngine != null; + } + + static MethodBase TargetMethod( HarmonyInstance instance ) + { + return AccessTools.Method( Constants.Types.AdvEngine, "JumpScenario", new Type[] { typeof( string ) } ); + } + + static void Prefix( ref string label ) + { + UtageHelpers.FixLabel( ref label ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/IKnownEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/IKnownEndpoint.cs new file mode 100644 index 00000000..e1b237a5 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/IKnownEndpoint.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections; +using System.IO; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public interface IKnownEndpoint + { + /// + /// Attempt to translated the provided untranslated text. Will be used in a "coroutine", so it can be implemented + /// in an async fashion. + /// + IEnumerator Translate( string untranslatedText, string from, string to, Action success, Action failure ); + + /// + /// Gets a boolean indicating if we are allowed to call "Translate". + /// + bool IsBusy { get; } + + /// + /// "Update" game loop method. + /// + void OnUpdate(); + + /// + /// Gets a bool indicating if the plugin is capable of distinguishing between the untranslated text + /// on a line per line basis. + /// + bool SupportsLineSplitting { get; } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/KnownEndpoints.cs b/src/XUnity.AutoTranslator.Plugin.Core/KnownEndpoints.cs new file mode 100644 index 00000000..696e1667 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/KnownEndpoints.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Web; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public static class KnownEndpoints + { + public static IKnownEndpoint FindEndpoint( string identifier ) + { + if( string.IsNullOrEmpty( identifier ) ) return null; + + switch( identifier ) + { + case KnownEndpointNames.GoogleTranslate: + case KnownEndpointNames.GoogleTranslateHack: + return new GoogleTranslateEndpoint(); + //return new GoogleTranslateHackEndpoint(); + case KnownEndpointNames.GoogleTranslateLegitimate: + return new GoogleTranslateLegitimateEndpoint(); + case KnownEndpointNames.BaiduTranslate: + return new BaiduTranslateEndpoint(); + case KnownEndpointNames.YandexTranslate: + return new YandexTranslateEndpoint(); + case KnownEndpointNames.WatsonTranslate: + return new WatsonTranslateEndpoint(); + case KnownEndpointNames.ExciteTranslate: + return new ExciteTranslateEndpoint(); + default: + return new DefaultEndpoint( identifier ); + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/LogLevel.cs b/src/XUnity.AutoTranslator.Plugin.Core/LogLevel.cs new file mode 100644 index 00000000..dd6763a8 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/LogLevel.cs @@ -0,0 +1,10 @@ +namespace XUnity.AutoTranslator.Plugin.Core +{ + public enum LogLevel + { + Debug, + Info, + Warn, + Error + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Logger.cs b/src/XUnity.AutoTranslator.Plugin.Core/Logger.cs new file mode 100644 index 00000000..e91106d8 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Logger.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core.Configuration; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public abstract class Logger + { + public static Logger Current; + + public Logger() + { + RespectSettings = true; + } + + public bool RespectSettings { get; protected set; } + + public void Error( Exception e, string message ) + { + Log( LogLevel.Error, message + Environment.NewLine + e ); + } + + public void Error( string message ) + { + Log( LogLevel.Error, message ); + } + + public void Warn( Exception e, string message ) + { + Log( LogLevel.Warn, message + Environment.NewLine + e ); + } + + public void Warn( string message ) + { + Log( LogLevel.Warn, message ); + } + + public void Info( Exception e, string message ) + { + Log( LogLevel.Info, message + Environment.NewLine + e ); + } + + public void Info( string message ) + { + Log( LogLevel.Info, message ); + } + + public void Debug( Exception e, string message ) + { + if( Settings.EnableDebugLogs || !RespectSettings ) + { + Log( LogLevel.Debug, message + Environment.NewLine + e ); + } + } + + public void Debug( string message ) + { + if( Settings.EnableDebugLogs || !RespectSettings ) + { + Log( LogLevel.Debug, message ); + } + } + + protected abstract void Log( LogLevel level, string message ); + + protected string GetPrefix( LogLevel level ) + { + switch( level ) + { + case LogLevel.Debug: + return "[DEBUG][XUnity.AutoTranslator]: "; + case LogLevel.Info: + return "[INFO][XUnity.AutoTranslator]: "; + case LogLevel.Warn: + return "[WARN][XUnity.AutoTranslator]: "; + case LogLevel.Error: + return "[ERROR][XUnity.AutoTranslator]: "; + default: + return "[UNKNOW][XUnity.AutoTranslator]: "; + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/Helpers.cs b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/Helpers.cs new file mode 100644 index 00000000..9ba9baf3 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/Helpers.cs @@ -0,0 +1,38 @@ +// +// System.Web.Util.Helpers +// +// Authors: +// Marek Habersack (mhabersack@novell.com) +// +// (C) 2009 Novell, Inc (http://novell.com) + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; +using System.Globalization; + +namespace RestSharp.Contrib +{ + class Helpers + { + public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture; + } +} \ No newline at end of file diff --git a/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HtmlEncoder.cs b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HtmlEncoder.cs new file mode 100644 index 00000000..c8b8eec2 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HtmlEncoder.cs @@ -0,0 +1,918 @@ +// +// Authors: +// Patrik Torstensson (Patrik.Torstensson@labs2.com) +// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) +// Tim Coleman (tim@timcoleman.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) + +// Marek Habersack +// +// (C) 2005-2010 Novell, Inc (http://novell.com/) +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Text; +#if NET_4_0 +using System.Web.Configuration; +#endif + +namespace RestSharp.Contrib +{ +#if NET_4_0 + public +#endif + class HttpEncoder + { + static char[] hexChars = "0123456789abcdef".ToCharArray(); + static object entitiesLock = new object(); + static SortedDictionary entities; +#if NET_4_0 + static Lazy defaultEncoder; + static Lazy currentEncoderLazy; +#else + static HttpEncoder defaultEncoder; +#endif + static HttpEncoder currentEncoder; + + static IDictionary Entities + { + get + { + lock (entitiesLock) + { + if (entities == null) + InitEntities(); + + return entities; + } + } + } + + public static HttpEncoder Current + { + get + { +#if NET_4_0 + if (currentEncoder == null) + currentEncoder = currentEncoderLazy.Value; +#endif + return currentEncoder; + } +#if NET_4_0 + set { + if (value == null) + throw new ArgumentNullException ("value"); + currentEncoder = value; + } +#endif + } + + public static HttpEncoder Default + { + get + { +#if NET_4_0 + return defaultEncoder.Value; +#else + return defaultEncoder; +#endif + } + } + + static HttpEncoder() + { +#if NET_4_0 + defaultEncoder = new Lazy (() => new HttpEncoder ()); + currentEncoderLazy = new Lazy (new Func (GetCustomEncoderFromConfig)); +#else + defaultEncoder = new HttpEncoder(); + currentEncoder = defaultEncoder; +#endif + } + + public HttpEncoder() + { + } +#if NET_4_0 + protected internal virtual +#else + internal static +#endif + void HeaderNameValueEncode(string headerName, string headerValue, out string encodedHeaderName, out string encodedHeaderValue) + { + if (String.IsNullOrEmpty(headerName)) + encodedHeaderName = headerName; + else + encodedHeaderName = EncodeHeaderString(headerName); + + if (String.IsNullOrEmpty(headerValue)) + encodedHeaderValue = headerValue; + else + encodedHeaderValue = EncodeHeaderString(headerValue); + } + + static void StringBuilderAppend(string s, ref StringBuilder sb) + { + if (sb == null) + sb = new StringBuilder(s); + else + sb.Append(s); + } + + static string EncodeHeaderString(string input) + { + StringBuilder sb = null; + char ch; + + for (int i = 0; i < input.Length; i++) + { + ch = input[i]; + + if ((ch < 32 && ch != 9) || ch == 127) + StringBuilderAppend(String.Format("%{0:x2}", (int)ch), ref sb); + } + + if (sb != null) + return sb.ToString(); + + return input; + } +#if NET_4_0 + protected internal virtual void HtmlAttributeEncode (string value, TextWriter output) + { + + if (output == null) + throw new ArgumentNullException ("output"); + + if (String.IsNullOrEmpty (value)) + return; + + output.Write (HtmlAttributeEncode (value)); + } + + protected internal virtual void HtmlDecode (string value, TextWriter output) + { + if (output == null) + throw new ArgumentNullException ("output"); + + output.Write (HtmlDecode (value)); + } + + protected internal virtual void HtmlEncode (string value, TextWriter output) + { + if (output == null) + throw new ArgumentNullException ("output"); + + output.Write (HtmlEncode (value)); + } + + protected internal virtual byte[] UrlEncode (byte[] bytes, int offset, int count) + { + return UrlEncodeToBytes (bytes, offset, count); + } + + static HttpEncoder GetCustomEncoderFromConfig () + { + var cfg = WebConfigurationManager.GetSection ("system.web/httpRuntime") as HttpRuntimeSection; + string typeName = cfg.EncoderType; + + if (String.Compare (typeName, "System.Web.Util.HttpEncoder", StringComparison.OrdinalIgnoreCase) == 0) + return Default; + + Type t = Type.GetType (typeName, false); + if (t == null) + throw new ConfigurationErrorsException (String.Format ("Could not load type '{0}'.", typeName)); + + if (!typeof (HttpEncoder).IsAssignableFrom (t)) + throw new ConfigurationErrorsException ( + String.Format ("'{0}' is not allowed here because it does not extend class 'System.Web.Util.HttpEncoder'.", typeName) + ); + + return Activator.CreateInstance (t, false) as HttpEncoder; + } +#endif +#if NET_4_0 + protected internal virtual +#else + internal static +#endif + string UrlPathEncode(string value) + { + if (String.IsNullOrEmpty(value)) + return value; + + MemoryStream result = new MemoryStream(); + int length = value.Length; + for (int i = 0; i < length; i++) + UrlPathEncodeChar(value[i], result); + + return Encoding.ASCII.GetString(result.ToArray()); + } + + internal static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) + { + if (bytes == null) + throw new ArgumentNullException("bytes"); + + int blen = bytes.Length; + if (blen == 0) + return new byte[0]; + + if (offset < 0 || offset >= blen) + throw new ArgumentOutOfRangeException("offset"); + + if (count < 0 || count > blen - offset) + throw new ArgumentOutOfRangeException("count"); + + MemoryStream result = new MemoryStream(count); + int end = offset + count; + for (int i = offset; i < end; i++) + UrlEncodeChar((char)bytes[i], result, false); + + return result.ToArray(); + } + + internal static string HtmlEncode(string s) + { + if (s == null) + return null; + + if (s.Length == 0) + return String.Empty; + + bool needEncode = false; + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159 +#if NET_4_0 + || c == '\'' +#endif +) + { + needEncode = true; + break; + } + } + + if (!needEncode) + return s; + + StringBuilder output = new StringBuilder(); + char ch; + int len = s.Length; + + for (int i = 0; i < len; i++) + { + switch (s[i]) + { + case '&': + output.Append("&"); + break; + case '>': + output.Append(">"); + break; + case '<': + output.Append("<"); + break; + case '"': + output.Append("""); + break; +#if NET_4_0 + case '\'': + output.Append ("'"); + break; +#endif + case '\uff1c': + output.Append("<"); + break; + + case '\uff1e': + output.Append(">"); + break; + + default: + ch = s[i]; + if (ch > 159 && ch < 256) + { + output.Append("&#"); + output.Append(((int)ch).ToString(Helpers.InvariantCulture)); + output.Append(";"); + } + else + output.Append(ch); + break; + } + } + + return output.ToString(); + } + + internal static string HtmlAttributeEncode(string s) + { +#if NET_4_0 + if (String.IsNullOrEmpty (s)) + return String.Empty; +#else + if (s == null) + return null; + + if (s.Length == 0) + return String.Empty; +#endif + bool needEncode = false; + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + if (c == '&' || c == '"' || c == '<' +#if NET_4_0 + || c == '\'' +#endif +) + { + needEncode = true; + break; + } + } + + if (!needEncode) + return s; + + StringBuilder output = new StringBuilder(); + int len = s.Length; + for (int i = 0; i < len; i++) + switch (s[i]) + { + case '&': + output.Append("&"); + break; + case '"': + output.Append("""); + break; + case '<': + output.Append("<"); + break; +#if NET_4_0 + case '\'': + output.Append ("'"); + break; +#endif + default: + output.Append(s[i]); + break; + } + + return output.ToString(); + } + + internal static string HtmlDecode(string s) + { + if (s == null) + return null; + + if (s.Length == 0) + return String.Empty; + + if (s.IndexOf('&') == -1) + return s; +#if NET_4_0 + StringBuilder rawEntity = new StringBuilder (); +#endif + StringBuilder entity = new StringBuilder(); + StringBuilder output = new StringBuilder(); + int len = s.Length; + // 0 -> nothing, + // 1 -> right after '&' + // 2 -> between '&' and ';' but no '#' + // 3 -> '#' found after '&' and getting numbers + int state = 0; + int number = 0; + bool is_hex_value = false; + bool have_trailing_digits = false; + + for (int i = 0; i < len; i++) + { + char c = s[i]; + if (state == 0) + { + if (c == '&') + { + entity.Append(c); +#if NET_4_0 + rawEntity.Append (c); +#endif + state = 1; + } + else + { + output.Append(c); + } + continue; + } + + if (c == '&') + { + state = 1; + if (have_trailing_digits) + { + entity.Append(number.ToString(Helpers.InvariantCulture)); + have_trailing_digits = false; + } + + output.Append(entity.ToString()); + entity.Length = 0; + entity.Append('&'); + continue; + } + + if (state == 1) + { + if (c == ';') + { + state = 0; + output.Append(entity.ToString()); + output.Append(c); + entity.Length = 0; + } + else + { + number = 0; + is_hex_value = false; + if (c != '#') + { + state = 2; + } + else + { + state = 3; + } + entity.Append(c); +#if NET_4_0 + rawEntity.Append (c); +#endif + } + } + else if (state == 2) + { + entity.Append(c); + if (c == ';') + { + string key = entity.ToString(); + if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2))) + key = Entities[key.Substring(1, key.Length - 2)].ToString(); + + output.Append(key); + state = 0; + entity.Length = 0; +#if NET_4_0 + rawEntity.Length = 0; +#endif + } + } + else if (state == 3) + { + if (c == ';') + { +#if NET_4_0 + if (number == 0) + output.Append (rawEntity.ToString () + ";"); + else +#endif + if (number > 65535) + { + output.Append("&#"); + output.Append(number.ToString(Helpers.InvariantCulture)); + output.Append(";"); + } + else + { + output.Append((char)number); + } + state = 0; + entity.Length = 0; +#if NET_4_0 + rawEntity.Length = 0; +#endif + have_trailing_digits = false; + } + else if (is_hex_value && Uri.IsHexDigit(c)) + { + number = number * 16 + Uri.FromHex(c); + have_trailing_digits = true; +#if NET_4_0 + rawEntity.Append (c); +#endif + } + else if (Char.IsDigit(c)) + { + number = number * 10 + ((int)c - '0'); + have_trailing_digits = true; +#if NET_4_0 + rawEntity.Append (c); +#endif + } + else if (number == 0 && (c == 'x' || c == 'X')) + { + is_hex_value = true; +#if NET_4_0 + rawEntity.Append (c); +#endif + } + else + { + state = 2; + if (have_trailing_digits) + { + entity.Append(number.ToString(Helpers.InvariantCulture)); + have_trailing_digits = false; + } + entity.Append(c); + } + } + } + + if (entity.Length > 0) + { + output.Append(entity.ToString()); + } + else if (have_trailing_digits) + { + output.Append(number.ToString(Helpers.InvariantCulture)); + } + return output.ToString(); + } + + internal static bool NotEncoded(char c) + { + return (c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_' +#if !NET_4_0 + || c == '\'' +#endif +); + } + + internal static void UrlEncodeChar(char c, Stream result, bool isUnicode) + { + if (c > 255) + { + //FIXME: what happens when there is an internal error? + //if (!isUnicode) + // throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256"); + int idx; + int i = (int)c; + + result.WriteByte((byte)'%'); + result.WriteByte((byte)'u'); + idx = i >> 12; + result.WriteByte((byte)hexChars[idx]); + idx = (i >> 8) & 0x0F; + result.WriteByte((byte)hexChars[idx]); + idx = (i >> 4) & 0x0F; + result.WriteByte((byte)hexChars[idx]); + idx = i & 0x0F; + result.WriteByte((byte)hexChars[idx]); + return; + } + + if (c > ' ' && NotEncoded(c)) + { + result.WriteByte((byte)c); + return; + } + if (c == ' ') + { + result.WriteByte((byte)'+'); + return; + } + if ((c < '0') || + (c < 'A' && c > '9') || + (c > 'Z' && c < 'a') || + (c > 'z')) + { + if (isUnicode && c > 127) + { + result.WriteByte((byte)'%'); + result.WriteByte((byte)'u'); + result.WriteByte((byte)'0'); + result.WriteByte((byte)'0'); + } + else + result.WriteByte((byte)'%'); + + int idx = ((int)c) >> 4; + result.WriteByte((byte)hexChars[idx]); + idx = ((int)c) & 0x0F; + result.WriteByte((byte)hexChars[idx]); + } + else + result.WriteByte((byte)c); + } + + internal static void UrlPathEncodeChar(char c, Stream result) + { + if (c < 33 || c > 126) + { + byte[] bIn = Encoding.UTF8.GetBytes(c.ToString()); + for (int i = 0; i < bIn.Length; i++) + { + result.WriteByte((byte)'%'); + int idx = ((int)bIn[i]) >> 4; + result.WriteByte((byte)hexChars[idx]); + idx = ((int)bIn[i]) & 0x0F; + result.WriteByte((byte)hexChars[idx]); + } + } + else if (c == ' ') + { + result.WriteByte((byte)'%'); + result.WriteByte((byte)'2'); + result.WriteByte((byte)'0'); + } + else + result.WriteByte((byte)c); + } + + static void InitEntities() + { + // Build the hash table of HTML entity references. This list comes + // from the HTML 4.01 W3C recommendation. + entities = new SortedDictionary(StringComparer.Ordinal); + + entities.Add("nbsp", '\u00A0'); + entities.Add("iexcl", '\u00A1'); + entities.Add("cent", '\u00A2'); + entities.Add("pound", '\u00A3'); + entities.Add("curren", '\u00A4'); + entities.Add("yen", '\u00A5'); + entities.Add("brvbar", '\u00A6'); + entities.Add("sect", '\u00A7'); + entities.Add("uml", '\u00A8'); + entities.Add("copy", '\u00A9'); + entities.Add("ordf", '\u00AA'); + entities.Add("laquo", '\u00AB'); + entities.Add("not", '\u00AC'); + entities.Add("shy", '\u00AD'); + entities.Add("reg", '\u00AE'); + entities.Add("macr", '\u00AF'); + entities.Add("deg", '\u00B0'); + entities.Add("plusmn", '\u00B1'); + entities.Add("sup2", '\u00B2'); + entities.Add("sup3", '\u00B3'); + entities.Add("acute", '\u00B4'); + entities.Add("micro", '\u00B5'); + entities.Add("para", '\u00B6'); + entities.Add("middot", '\u00B7'); + entities.Add("cedil", '\u00B8'); + entities.Add("sup1", '\u00B9'); + entities.Add("ordm", '\u00BA'); + entities.Add("raquo", '\u00BB'); + entities.Add("frac14", '\u00BC'); + entities.Add("frac12", '\u00BD'); + entities.Add("frac34", '\u00BE'); + entities.Add("iquest", '\u00BF'); + entities.Add("Agrave", '\u00C0'); + entities.Add("Aacute", '\u00C1'); + entities.Add("Acirc", '\u00C2'); + entities.Add("Atilde", '\u00C3'); + entities.Add("Auml", '\u00C4'); + entities.Add("Aring", '\u00C5'); + entities.Add("AElig", '\u00C6'); + entities.Add("Ccedil", '\u00C7'); + entities.Add("Egrave", '\u00C8'); + entities.Add("Eacute", '\u00C9'); + entities.Add("Ecirc", '\u00CA'); + entities.Add("Euml", '\u00CB'); + entities.Add("Igrave", '\u00CC'); + entities.Add("Iacute", '\u00CD'); + entities.Add("Icirc", '\u00CE'); + entities.Add("Iuml", '\u00CF'); + entities.Add("ETH", '\u00D0'); + entities.Add("Ntilde", '\u00D1'); + entities.Add("Ograve", '\u00D2'); + entities.Add("Oacute", '\u00D3'); + entities.Add("Ocirc", '\u00D4'); + entities.Add("Otilde", '\u00D5'); + entities.Add("Ouml", '\u00D6'); + entities.Add("times", '\u00D7'); + entities.Add("Oslash", '\u00D8'); + entities.Add("Ugrave", '\u00D9'); + entities.Add("Uacute", '\u00DA'); + entities.Add("Ucirc", '\u00DB'); + entities.Add("Uuml", '\u00DC'); + entities.Add("Yacute", '\u00DD'); + entities.Add("THORN", '\u00DE'); + entities.Add("szlig", '\u00DF'); + entities.Add("agrave", '\u00E0'); + entities.Add("aacute", '\u00E1'); + entities.Add("acirc", '\u00E2'); + entities.Add("atilde", '\u00E3'); + entities.Add("auml", '\u00E4'); + entities.Add("aring", '\u00E5'); + entities.Add("aelig", '\u00E6'); + entities.Add("ccedil", '\u00E7'); + entities.Add("egrave", '\u00E8'); + entities.Add("eacute", '\u00E9'); + entities.Add("ecirc", '\u00EA'); + entities.Add("euml", '\u00EB'); + entities.Add("igrave", '\u00EC'); + entities.Add("iacute", '\u00ED'); + entities.Add("icirc", '\u00EE'); + entities.Add("iuml", '\u00EF'); + entities.Add("eth", '\u00F0'); + entities.Add("ntilde", '\u00F1'); + entities.Add("ograve", '\u00F2'); + entities.Add("oacute", '\u00F3'); + entities.Add("ocirc", '\u00F4'); + entities.Add("otilde", '\u00F5'); + entities.Add("ouml", '\u00F6'); + entities.Add("divide", '\u00F7'); + entities.Add("oslash", '\u00F8'); + entities.Add("ugrave", '\u00F9'); + entities.Add("uacute", '\u00FA'); + entities.Add("ucirc", '\u00FB'); + entities.Add("uuml", '\u00FC'); + entities.Add("yacute", '\u00FD'); + entities.Add("thorn", '\u00FE'); + entities.Add("yuml", '\u00FF'); + entities.Add("fnof", '\u0192'); + entities.Add("Alpha", '\u0391'); + entities.Add("Beta", '\u0392'); + entities.Add("Gamma", '\u0393'); + entities.Add("Delta", '\u0394'); + entities.Add("Epsilon", '\u0395'); + entities.Add("Zeta", '\u0396'); + entities.Add("Eta", '\u0397'); + entities.Add("Theta", '\u0398'); + entities.Add("Iota", '\u0399'); + entities.Add("Kappa", '\u039A'); + entities.Add("Lambda", '\u039B'); + entities.Add("Mu", '\u039C'); + entities.Add("Nu", '\u039D'); + entities.Add("Xi", '\u039E'); + entities.Add("Omicron", '\u039F'); + entities.Add("Pi", '\u03A0'); + entities.Add("Rho", '\u03A1'); + entities.Add("Sigma", '\u03A3'); + entities.Add("Tau", '\u03A4'); + entities.Add("Upsilon", '\u03A5'); + entities.Add("Phi", '\u03A6'); + entities.Add("Chi", '\u03A7'); + entities.Add("Psi", '\u03A8'); + entities.Add("Omega", '\u03A9'); + entities.Add("alpha", '\u03B1'); + entities.Add("beta", '\u03B2'); + entities.Add("gamma", '\u03B3'); + entities.Add("delta", '\u03B4'); + entities.Add("epsilon", '\u03B5'); + entities.Add("zeta", '\u03B6'); + entities.Add("eta", '\u03B7'); + entities.Add("theta", '\u03B8'); + entities.Add("iota", '\u03B9'); + entities.Add("kappa", '\u03BA'); + entities.Add("lambda", '\u03BB'); + entities.Add("mu", '\u03BC'); + entities.Add("nu", '\u03BD'); + entities.Add("xi", '\u03BE'); + entities.Add("omicron", '\u03BF'); + entities.Add("pi", '\u03C0'); + entities.Add("rho", '\u03C1'); + entities.Add("sigmaf", '\u03C2'); + entities.Add("sigma", '\u03C3'); + entities.Add("tau", '\u03C4'); + entities.Add("upsilon", '\u03C5'); + entities.Add("phi", '\u03C6'); + entities.Add("chi", '\u03C7'); + entities.Add("psi", '\u03C8'); + entities.Add("omega", '\u03C9'); + entities.Add("thetasym", '\u03D1'); + entities.Add("upsih", '\u03D2'); + entities.Add("piv", '\u03D6'); + entities.Add("bull", '\u2022'); + entities.Add("hellip", '\u2026'); + entities.Add("prime", '\u2032'); + entities.Add("Prime", '\u2033'); + entities.Add("oline", '\u203E'); + entities.Add("frasl", '\u2044'); + entities.Add("weierp", '\u2118'); + entities.Add("image", '\u2111'); + entities.Add("real", '\u211C'); + entities.Add("trade", '\u2122'); + entities.Add("alefsym", '\u2135'); + entities.Add("larr", '\u2190'); + entities.Add("uarr", '\u2191'); + entities.Add("rarr", '\u2192'); + entities.Add("darr", '\u2193'); + entities.Add("harr", '\u2194'); + entities.Add("crarr", '\u21B5'); + entities.Add("lArr", '\u21D0'); + entities.Add("uArr", '\u21D1'); + entities.Add("rArr", '\u21D2'); + entities.Add("dArr", '\u21D3'); + entities.Add("hArr", '\u21D4'); + entities.Add("forall", '\u2200'); + entities.Add("part", '\u2202'); + entities.Add("exist", '\u2203'); + entities.Add("empty", '\u2205'); + entities.Add("nabla", '\u2207'); + entities.Add("isin", '\u2208'); + entities.Add("notin", '\u2209'); + entities.Add("ni", '\u220B'); + entities.Add("prod", '\u220F'); + entities.Add("sum", '\u2211'); + entities.Add("minus", '\u2212'); + entities.Add("lowast", '\u2217'); + entities.Add("radic", '\u221A'); + entities.Add("prop", '\u221D'); + entities.Add("infin", '\u221E'); + entities.Add("ang", '\u2220'); + entities.Add("and", '\u2227'); + entities.Add("or", '\u2228'); + entities.Add("cap", '\u2229'); + entities.Add("cup", '\u222A'); + entities.Add("int", '\u222B'); + entities.Add("there4", '\u2234'); + entities.Add("sim", '\u223C'); + entities.Add("cong", '\u2245'); + entities.Add("asymp", '\u2248'); + entities.Add("ne", '\u2260'); + entities.Add("equiv", '\u2261'); + entities.Add("le", '\u2264'); + entities.Add("ge", '\u2265'); + entities.Add("sub", '\u2282'); + entities.Add("sup", '\u2283'); + entities.Add("nsub", '\u2284'); + entities.Add("sube", '\u2286'); + entities.Add("supe", '\u2287'); + entities.Add("oplus", '\u2295'); + entities.Add("otimes", '\u2297'); + entities.Add("perp", '\u22A5'); + entities.Add("sdot", '\u22C5'); + entities.Add("lceil", '\u2308'); + entities.Add("rceil", '\u2309'); + entities.Add("lfloor", '\u230A'); + entities.Add("rfloor", '\u230B'); + entities.Add("lang", '\u2329'); + entities.Add("rang", '\u232A'); + entities.Add("loz", '\u25CA'); + entities.Add("spades", '\u2660'); + entities.Add("clubs", '\u2663'); + entities.Add("hearts", '\u2665'); + entities.Add("diams", '\u2666'); + entities.Add("quot", '\u0022'); + entities.Add("amp", '\u0026'); + entities.Add("lt", '\u003C'); + entities.Add("gt", '\u003E'); + entities.Add("OElig", '\u0152'); + entities.Add("oelig", '\u0153'); + entities.Add("Scaron", '\u0160'); + entities.Add("scaron", '\u0161'); + entities.Add("Yuml", '\u0178'); + entities.Add("circ", '\u02C6'); + entities.Add("tilde", '\u02DC'); + entities.Add("ensp", '\u2002'); + entities.Add("emsp", '\u2003'); + entities.Add("thinsp", '\u2009'); + entities.Add("zwnj", '\u200C'); + entities.Add("zwj", '\u200D'); + entities.Add("lrm", '\u200E'); + entities.Add("rlm", '\u200F'); + entities.Add("ndash", '\u2013'); + entities.Add("mdash", '\u2014'); + entities.Add("lsquo", '\u2018'); + entities.Add("rsquo", '\u2019'); + entities.Add("sbquo", '\u201A'); + entities.Add("ldquo", '\u201C'); + entities.Add("rdquo", '\u201D'); + entities.Add("bdquo", '\u201E'); + entities.Add("dagger", '\u2020'); + entities.Add("Dagger", '\u2021'); + entities.Add("permil", '\u2030'); + entities.Add("lsaquo", '\u2039'); + entities.Add("rsaquo", '\u203A'); + entities.Add("euro", '\u20AC'); + } + } +} \ No newline at end of file diff --git a/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HttpUtility.cs b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HttpUtility.cs new file mode 100644 index 00000000..64f7775a --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HttpUtility.cs @@ -0,0 +1,766 @@ +// +// System.Web.HttpUtility +// +// Authors: +// Patrik Torstensson (Patrik.Torstensson@labs2.com) +// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) +// Tim Coleman (tim@timcoleman.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Security.Permissions; +using System.Text; + +namespace RestSharp.Contrib +{ + +//#if !MONOTOUCH +// // CAS - no InheritanceDemand here as the class is sealed +// [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] +//#endif + public sealed class HttpUtility + { + sealed class HttpQSCollection : NameValueCollection + { + public override string ToString() + { + int count = Count; + if (count == 0) + return ""; + StringBuilder sb = new StringBuilder(); + string[] keys = AllKeys; + for (int i = 0; i < count; i++) + { + sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]); + } + if (sb.Length > 0) + sb.Length--; + return sb.ToString(); + } + } + + #region Constructors + + public HttpUtility() + { + } + + #endregion // Constructors + + #region Methods + + public static void HtmlAttributeEncode(string s, TextWriter output) + { + if (output == null) + { +#if NET_4_0 + throw new ArgumentNullException ("output"); +#else + throw new NullReferenceException(".NET emulation"); +#endif + } +#if NET_4_0 + HttpEncoder.Current.HtmlAttributeEncode (s, output); +#else + output.Write(HttpEncoder.HtmlAttributeEncode(s)); +#endif + } + + public static string HtmlAttributeEncode(string s) + { +#if NET_4_0 + if (s == null) + return null; + + using (var sw = new StringWriter ()) { + HttpEncoder.Current.HtmlAttributeEncode (s, sw); + return sw.ToString (); + } +#else + return HttpEncoder.HtmlAttributeEncode(s); +#endif + } + + public static string UrlDecode(string str) + { + return UrlDecode(str, Encoding.UTF8); + } + + static char[] GetChars(MemoryStream b, Encoding e) + { + return e.GetChars(b.GetBuffer(), 0, (int)b.Length); + } + + static void WriteCharBytes(IList buf, char ch, Encoding e) + { + if (ch > 255) + { + foreach (byte b in e.GetBytes(new char[] { ch })) + buf.Add(b); + } + else + buf.Add((byte)ch); + } + + public static string UrlDecode(string s, Encoding e) + { + if (null == s) + return null; + + if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) + return s; + + if (e == null) + e = Encoding.UTF8; + + long len = s.Length; + var bytes = new List(); + int xchar; + char ch; + + for (int i = 0; i < len; i++) + { + ch = s[i]; + if (ch == '%' && i + 2 < len && s[i + 1] != '%') + { + if (s[i + 1] == 'u' && i + 5 < len) + { + // unicode hex sequence + xchar = GetChar(s, i + 2, 4); + if (xchar != -1) + { + WriteCharBytes(bytes, (char)xchar, e); + i += 5; + } + else + WriteCharBytes(bytes, '%', e); + } + else if ((xchar = GetChar(s, i + 1, 2)) != -1) + { + WriteCharBytes(bytes, (char)xchar, e); + i += 2; + } + else + { + WriteCharBytes(bytes, '%', e); + } + continue; + } + + if (ch == '+') + WriteCharBytes(bytes, ' ', e); + else + WriteCharBytes(bytes, ch, e); + } + + byte[] buf = bytes.ToArray(); + bytes = null; + return e.GetString(buf); + + } + + public static string UrlDecode(byte[] bytes, Encoding e) + { + if (bytes == null) + return null; + + return UrlDecode(bytes, 0, bytes.Length, e); + } + + static int GetInt(byte b) + { + char c = (char)b; + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; + } + + static int GetChar(byte[] bytes, int offset, int length) + { + int value = 0; + int end = length + offset; + for (int i = offset; i < end; i++) + { + int current = GetInt(bytes[i]); + if (current == -1) + return -1; + value = (value << 4) + current; + } + + return value; + } + + static int GetChar(string str, int offset, int length) + { + int val = 0; + int end = length + offset; + for (int i = offset; i < end; i++) + { + char c = str[i]; + if (c > 127) + return -1; + + int current = GetInt((byte)c); + if (current == -1) + return -1; + val = (val << 4) + current; + } + + return val; + } + + public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) + { + if (bytes == null) + return null; + if (count == 0) + return String.Empty; + + if (bytes == null) + throw new ArgumentNullException("bytes"); + + if (offset < 0 || offset > bytes.Length) + throw new ArgumentOutOfRangeException("offset"); + + if (count < 0 || offset + count > bytes.Length) + throw new ArgumentOutOfRangeException("count"); + + StringBuilder output = new StringBuilder(); + MemoryStream acc = new MemoryStream(); + + int end = count + offset; + int xchar; + for (int i = offset; i < end; i++) + { + if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%') + { + if (bytes[i + 1] == (byte)'u' && i + 5 < end) + { + if (acc.Length > 0) + { + output.Append(GetChars(acc, e)); + acc.SetLength(0); + } + xchar = GetChar(bytes, i + 2, 4); + if (xchar != -1) + { + output.Append((char)xchar); + i += 5; + continue; + } + } + else if ((xchar = GetChar(bytes, i + 1, 2)) != -1) + { + acc.WriteByte((byte)xchar); + i += 2; + continue; + } + } + + if (acc.Length > 0) + { + output.Append(GetChars(acc, e)); + acc.SetLength(0); + } + + if (bytes[i] == '+') + { + output.Append(' '); + } + else + { + output.Append((char)bytes[i]); + } + } + + if (acc.Length > 0) + { + output.Append(GetChars(acc, e)); + } + + acc = null; + return output.ToString(); + } + + public static byte[] UrlDecodeToBytes(byte[] bytes) + { + if (bytes == null) + return null; + + return UrlDecodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlDecodeToBytes(string str) + { + return UrlDecodeToBytes(str, Encoding.UTF8); + } + + public static byte[] UrlDecodeToBytes(string str, Encoding e) + { + if (str == null) + return null; + + if (e == null) + throw new ArgumentNullException("e"); + + return UrlDecodeToBytes(e.GetBytes(str)); + } + + public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) + { + if (bytes == null) + return null; + if (count == 0) + return new byte[0]; + + int len = bytes.Length; + if (offset < 0 || offset >= len) + throw new ArgumentOutOfRangeException("offset"); + + if (count < 0 || offset > len - count) + throw new ArgumentOutOfRangeException("count"); + + MemoryStream result = new MemoryStream(); + int end = offset + count; + for (int i = offset; i < end; i++) + { + char c = (char)bytes[i]; + if (c == '+') + { + c = ' '; + } + else if (c == '%' && i < end - 2) + { + int xchar = GetChar(bytes, i + 1, 2); + if (xchar != -1) + { + c = (char)xchar; + i += 2; + } + } + result.WriteByte((byte)c); + } + + return result.ToArray(); + } + + public static string UrlEncode(string str) + { + return UrlEncode(str, Encoding.UTF8); + } + + public static string UrlEncode(string s, Encoding Enc) + { + if (s == null) + return null; + + if (s == String.Empty) + return String.Empty; + + bool needEncode = false; + int len = s.Length; + for (int i = 0; i < len; i++) + { + char c = s[i]; + if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) + { + if (HttpEncoder.NotEncoded(c)) + continue; + + needEncode = true; + break; + } + } + + if (!needEncode) + return s; + + // avoided GetByteCount call + byte[] bytes = new byte[Enc.GetMaxByteCount(s.Length)]; + int realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0); + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen)); + } + + public static string UrlEncode(byte[] bytes) + { + if (bytes == null) + return null; + + if (bytes.Length == 0) + return String.Empty; + + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length)); + } + + public static string UrlEncode(byte[] bytes, int offset, int count) + { + if (bytes == null) + return null; + + if (bytes.Length == 0) + return String.Empty; + + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count)); + } + + public static byte[] UrlEncodeToBytes(string str) + { + return UrlEncodeToBytes(str, Encoding.UTF8); + } + + public static byte[] UrlEncodeToBytes(string str, Encoding e) + { + if (str == null) + return null; + + if (str.Length == 0) + return new byte[0]; + + byte[] bytes = e.GetBytes(str); + return UrlEncodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlEncodeToBytes(byte[] bytes) + { + if (bytes == null) + return null; + + if (bytes.Length == 0) + return new byte[0]; + + return UrlEncodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) + { + if (bytes == null) + return null; +#if NET_4_0 + return HttpEncoder.Current.UrlEncode (bytes, offset, count); +#else + return HttpEncoder.UrlEncodeToBytes(bytes, offset, count); +#endif + } + + public static string UrlEncodeUnicode(string str) + { + if (str == null) + return null; + + return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str)); + } + + public static byte[] UrlEncodeUnicodeToBytes(string str) + { + if (str == null) + return null; + + if (str.Length == 0) + return new byte[0]; + + MemoryStream result = new MemoryStream(str.Length); + foreach (char c in str) + { + HttpEncoder.UrlEncodeChar(c, result, true); + } + return result.ToArray(); + } + + /// + /// Decodes an HTML-encoded string and returns the decoded string. + /// + /// The HTML string to decode. + /// The decoded text. + public static string HtmlDecode(string s) + { +#if NET_4_0 + if (s == null) + return null; + + using (var sw = new StringWriter ()) { + HttpEncoder.Current.HtmlDecode (s, sw); + return sw.ToString (); + } +#else + return HttpEncoder.HtmlDecode(s); +#endif + } + + /// + /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream. + /// + /// The HTML string to decode + /// The TextWriter output stream containing the decoded string. + public static void HtmlDecode(string s, TextWriter output) + { + if (output == null) + { +#if NET_4_0 + throw new ArgumentNullException ("output"); +#else + throw new NullReferenceException(".NET emulation"); +#endif + } + + if (!String.IsNullOrEmpty(s)) + { +#if NET_4_0 + HttpEncoder.Current.HtmlDecode (s, output); +#else + output.Write(HttpEncoder.HtmlDecode(s)); +#endif + } + } + + public static string HtmlEncode(string s) + { +#if NET_4_0 + if (s == null) + return null; + + using (var sw = new StringWriter ()) { + HttpEncoder.Current.HtmlEncode (s, sw); + return sw.ToString (); + } +#else + return HttpEncoder.HtmlEncode(s); +#endif + } + + /// + /// HTML-encodes a string and sends the resulting output to a TextWriter output stream. + /// + /// The string to encode. + /// The TextWriter output stream containing the encoded string. + public static void HtmlEncode(string s, TextWriter output) + { + if (output == null) + { +#if NET_4_0 + throw new ArgumentNullException ("output"); +#else + throw new NullReferenceException(".NET emulation"); +#endif + } + + if (!String.IsNullOrEmpty(s)) + { +#if NET_4_0 + HttpEncoder.Current.HtmlEncode (s, output); +#else + output.Write(HttpEncoder.HtmlEncode(s)); +#endif + } + } +#if NET_4_0 + public static string HtmlEncode (object value) + { + if (value == null) + return null; + + IHtmlString htmlString = value as IHtmlString; + if (htmlString != null) + return htmlString.ToHtmlString (); + + return HtmlEncode (value.ToString ()); + } + + public static string JavaScriptStringEncode (string value) + { + return JavaScriptStringEncode (value, false); + } + + public static string JavaScriptStringEncode (string value, bool addDoubleQuotes) + { + if (String.IsNullOrEmpty (value)) + return addDoubleQuotes ? "\"\"" : String.Empty; + + int len = value.Length; + bool needEncode = false; + char c; + for (int i = 0; i < len; i++) { + c = value [i]; + + if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) { + needEncode = true; + break; + } + } + + if (!needEncode) + return addDoubleQuotes ? "\"" + value + "\"" : value; + + var sb = new StringBuilder (); + if (addDoubleQuotes) + sb.Append ('"'); + + for (int i = 0; i < len; i++) { + c = value [i]; + if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62) + sb.AppendFormat ("\\u{0:x4}", (int)c); + else switch ((int)c) { + case 8: + sb.Append ("\\b"); + break; + + case 9: + sb.Append ("\\t"); + break; + + case 10: + sb.Append ("\\n"); + break; + + case 12: + sb.Append ("\\f"); + break; + + case 13: + sb.Append ("\\r"); + break; + + case 34: + sb.Append ("\\\""); + break; + + case 92: + sb.Append ("\\\\"); + break; + + default: + sb.Append (c); + break; + } + } + + if (addDoubleQuotes) + sb.Append ('"'); + + return sb.ToString (); + } +#endif + public static string UrlPathEncode(string s) + { +#if NET_4_0 + return HttpEncoder.Current.UrlPathEncode (s); +#else + return HttpEncoder.UrlPathEncode(s); +#endif + } + + public static NameValueCollection ParseQueryString(string query) + { + return ParseQueryString(query, Encoding.UTF8); + } + + public static NameValueCollection ParseQueryString(string query, Encoding encoding) + { + if (query == null) + throw new ArgumentNullException("query"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + if (query.Length == 0 || (query.Length == 1 && query[0] == '?')) + return new NameValueCollection(); + if (query[0] == '?') + query = query.Substring(1); + + NameValueCollection result = new HttpQSCollection(); + ParseQueryString(query, encoding, result); + return result; + } + + internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result) + { + if (query.Length == 0) + return; + + string decoded = HtmlDecode(query); + int decodedLength = decoded.Length; + int namePos = 0; + bool first = true; + while (namePos <= decodedLength) + { + int valuePos = -1, valueEnd = -1; + for (int q = namePos; q < decodedLength; q++) + { + if (valuePos == -1 && decoded[q] == '=') + { + valuePos = q + 1; + } + else if (decoded[q] == '&') + { + valueEnd = q; + break; + } + } + + if (first) + { + first = false; + if (decoded[namePos] == '?') + namePos++; + } + + string name, value; + if (valuePos == -1) + { + name = null; + valuePos = namePos; + } + else + { + name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding); + } + if (valueEnd < 0) + { + namePos = -1; + valueEnd = decoded.Length; + } + else + { + namePos = valueEnd + 1; + } + value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding); + + result.Add(name, value); + if (namePos == -1) + break; + } + } + #endregion // Methods + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Parsing/ParserResult.cs b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/ParserResult.cs new file mode 100644 index 00000000..62b0044a --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/ParserResult.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace XUnity.AutoTranslator.Plugin.Core.Parsing +{ + public class ParserResult + { + public ParserResult( string originalText, string template, Dictionary args ) + { + OriginalText = originalText; + Template = template; + Arguments = args; + } + + public string OriginalText { get; private set; } + + public string Template { get; private set; } + + public Dictionary Arguments { get; private set; } + + public bool HasRichSyntax => Template.Length > 5; // {{A}} <-- 5 chars + + public string Untemplate( Dictionary arguments ) + { + string result = Template; + foreach( var kvp in arguments ) + { + result = result.Replace( kvp.Key, kvp.Value ); + } + return result; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Parsing/RichTextParser.cs b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/RichTextParser.cs new file mode 100644 index 00000000..965b5a7c --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/RichTextParser.cs @@ -0,0 +1,130 @@ +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace XUnity.AutoTranslator.Plugin.Core.Parsing +{ + + public class RichTextParser + { + private static readonly char[] TagNameEnders = new char[] { '=', ' ' }; + private static readonly Regex TagRegex = new Regex( "<.*?>" ); + private static readonly HashSet IgnoreTags = new HashSet { "ruby", "group" }; + private static readonly HashSet KnownTags = new HashSet { "b", "i", "size", "color", "ruby", "em", "sup", "sub", "dash", "space", "group", "u", "strike", "param", "format", "emoji", "speed", "sound" }; + + public RichTextParser() + { + + } + + public ParserResult Parse( string input ) + { + var matches = TagRegex.Matches( input ); + + var accumulation = new StringBuilder(); + var args = new Dictionary(); + var template = new StringBuilder( input.Length ); + var offset = 0; + var arg = 'A'; + + foreach( Match m in matches ) + { + var tag = m.Value; + var value = tag.Substring( 1, tag.Length - 2 ); + bool isEndTag = value.StartsWith( "/" ); + if( isEndTag ) + { + value = value.Substring( 1, value.Length - 1 ); + } + + var parts = value.Split( TagNameEnders ); + if( parts.Length >= 2 ) + { + value = parts[ 0 ]; + } + var isKnown = KnownTags.Contains( value ); + var isIgnored = IgnoreTags.Contains( value ); + if( !isKnown ) + { + var endIdx = value.Length; + bool allLatin = true; + for( int j = 0 ; j < endIdx ; j++ ) + { + var c = value[ j ]; + if( !( ( c >= '\u0041' && c <= '\u005a' ) || ( c >= '\u0061' && c <= '\u007a' ) ) ) + { + allLatin = false; + break; + } + } + isKnown = allLatin; + } + + // add normal text + var end = m.Index; + var start = offset; + var text = input.Substring( start, end - start ); + offset = end + m.Length; + + // if the tag is not known, we want to include as normal text in the NEXT iteration + if( !isKnown ) + { + accumulation.Append( text ); + accumulation.Append( m.Value ); + } + else + { + text += accumulation; + accumulation.Length = 0; + + if( !string.IsNullOrEmpty( text ) ) + { + var argument = "{{" + ( arg++ ) + "}}"; + args.Add( argument, text ); + template.Append( argument ); + } + + if( !isIgnored ) + { + template.Append( m.Value ); + } + } + } + + // catch any remaining text + if( offset < input.Length ) + { + var argument = "{{" + ( arg++ ) + "}}"; + var text = input.Substring( offset, input.Length - offset ); + args.Add( argument, text ); + template.Append( argument ); + } + + + var templateString = template.ToString(); + int idx = -1; + while( ( idx = templateString.IndexOf( "}}{{" ) ) != -1 ) + { + var arg1 = templateString[ idx - 1 ]; + var arg2 = templateString[ idx + 4 ]; + + var key1 = "{{" + arg1 + "}}"; + var key2 = "{{" + arg2 + "}}"; + + var text1 = args[ key1 ]; + var text2 = args[ key2 ]; + + var fullText = text1 + text2; + var fullKey = key1 + key2; + var newKey = "{{" + ( ++arg ) + "}}"; + + args.Remove( key1 ); + args.Remove( key2 ); + args.Add( newKey, fullText ); + templateString = templateString.Replace( fullKey, newKey ); + } + + return new ParserResult( input, templateString, args ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Parsing/UnityTextParsers.cs b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/UnityTextParsers.cs new file mode 100644 index 00000000..fd2e265a --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Parsing/UnityTextParsers.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core.Constants; + +namespace XUnity.AutoTranslator.Plugin.Core.Parsing +{ + public static class UnityTextParsers + { + private static readonly RichTextParser RichTextParser = new RichTextParser(); + + public static RichTextParser GetTextParserByGameEngine() + { + return RichTextParser; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/PluginLoader.cs b/src/XUnity.AutoTranslator.Plugin.Core/PluginLoader.cs index 9e9d3307..5df1d3c1 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/PluginLoader.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/PluginLoader.cs @@ -23,7 +23,6 @@ public static void LoadWithConfig( IConfiguration config ) var obj = new GameObject( "Auto Translator" ); var instance = obj.AddComponent(); GameObject.DontDestroyOnLoad( obj ); - instance.Initialize(); } } @@ -46,19 +45,19 @@ private static void Bootstrapper_Destroyed() { Load(); } + } - class Bootstrapper : MonoBehaviour - { - public event Action Destroyed = delegate { }; + class Bootstrapper : MonoBehaviour + { + public event Action Destroyed = delegate { }; - void Start() - { - Destroy( gameObject ); - } - void OnDestroy() - { - Destroyed?.Invoke(); - } + void Start() + { + Destroy( gameObject ); + } + void OnDestroy() + { + Destroyed?.Invoke(); } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.Designer.cs b/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.Designer.cs new file mode 100644 index 00000000..09011def --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XUnity.AutoTranslator.Plugin.Core.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("XUnity.AutoTranslator.Plugin.Core.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to 【アイシャドウ】カラー=[Eye Shadow] Color + ///【アクセサリ(スロット01)】カラー=[Accessory 01] Color + ///【アクセサリ(スロット01)】ツヤの色=[Accessory 01] Shine Color + ///【アクセサリ(スロット02)】カラー=[Accessory 02] Color + ///【アクセサリ(スロット02)】ツヤの色=[Accessory 02] Shine Color + ///【アクセサリ(スロット03)】カラー=[Accessory 03] Color + ///【アクセサリ(スロット03)】ツヤの色=[Accessory 03] Shine Color + ///【アクセサリ(スロット04)】カラー=[Accessory 04] Color + ///【アクセサリ(スロット04)】ツヤの色=[Accessory 04] Shine Color + ///【アクセサリ(スロット05)】カラー=[Accessory 05] Color + ///【アクセサリ(スロット05)】ツヤの色=[Accessory 05] Shine Color + ///【アクセサリ(スロット06)】カラー=[Accessory 06] C [rest of string was truncated]";. + /// + internal static string StaticTranslations { + get { + return ResourceManager.GetString("StaticTranslations", resourceCulture); + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.resx b/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.resx new file mode 100644 index 00000000..03d35a90 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\translations\statictranslations.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Shim/CustomYieldInstructionShim.cs b/src/XUnity.AutoTranslator.Plugin.Core/Shim/CustomYieldInstructionShim.cs new file mode 100644 index 00000000..7683b081 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Shim/CustomYieldInstructionShim.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core.Shim +{ + public abstract class CustomYieldInstructionShim : IEnumerator + { + // Methods + protected CustomYieldInstructionShim() + { + } + + public bool MoveNext() + { + return keepWaiting; + } + + public void Reset() + { + } + + // Properties + public object Current + { + get + { + return null; + } + } + + public abstract bool keepWaiting { get; } + } + + +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/TemplatedString.cs b/src/XUnity.AutoTranslator.Plugin.Core/TemplatedString.cs new file mode 100644 index 00000000..b726fd86 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/TemplatedString.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public class TemplatedString + { + public TemplatedString( string template, Dictionary arguments ) + { + Template = template; + Arguments = arguments; + } + + public string Template { get; private set; } + + public Dictionary Arguments { get; private set; } + + public string Untemplate( string text ) + { + foreach( var kvp in Arguments ) + { + text = text.Replace( kvp.Key, kvp.Value ); + } + return text; + } + + public string RepairTemplate( string text ) + { + // TODO: Implement template repairation. The web services might have mangled our parameterization + return text; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/TranslationInfo.cs b/src/XUnity.AutoTranslator.Plugin.Core/TranslationInfo.cs index 0c6ccb4c..e32510ad 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/TranslationInfo.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/TranslationInfo.cs @@ -4,6 +4,8 @@ using System.Text; using UnityEngine; using UnityEngine.UI; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Fonts; namespace XUnity.AutoTranslator.Plugin.Core { @@ -13,7 +15,8 @@ public class TranslationInfo private static readonly string OverflowMethodPropertyName = "overflowMethod"; private static readonly string UILabelClassName = "UILabel"; - private Action _reset; + private Action _unresize; + private Action _unfont; public TranslationInfo() { @@ -29,35 +32,71 @@ public TranslationInfo() public bool IsCurrentlySettingText { get; set; } + public void ChangeFont( object graphic ) + { + if( graphic == null ) return; + + if( graphic is Text ) + { + var ui = graphic as Text; + + var previousFont = ui.font; + var newFont = FontCache.GetOrCreate( previousFont.fontSize ); + + ui.font = newFont; + if( _unfont == null ) + { + _unfont = obj => + { + ( (Text)obj ).font = previousFont; + }; + } + } + } + + public void UnchangeFont( object graphic ) + { + if( graphic == null ) return; + + _unfont?.Invoke( graphic ); + _unfont = null; + } + public void ResizeUI( object graphic ) { + // do not resize if there is no object of ir it is already resized + if( graphic == null ) return; + if( graphic is Text ) { var ui = (Text)graphic; // text is likely to be longer than there is space for, simply expand out anyway then - var width = ( (RectTransform)ui.transform ).rect.width; - var quarterScreenSize = Screen.width / 5; + var componentWidth = ( (RectTransform)ui.transform ).rect.width; + var quarterScreenSize = Screen.width / 4; + var isComponentWide = componentWidth > quarterScreenSize; // width < quarterScreenSize is used to determine the likelihood of a text using multiple lines // the idea is, if the UI element is larger than the width of half the screen, there is a larger // likelihood that it will go into multiple lines too. var originalHorizontalOverflow = ui.horizontalOverflow; - if( ui.verticalOverflow == VerticalWrapMode.Truncate && width < quarterScreenSize && !ui.resizeTextForBestFit ) - { - // will prevent the text from going into multiple lines and from "dispearing" if there is not enough room on a single line - ui.horizontalOverflow = HorizontalWrapMode.Overflow; - } - else + var originalVerticalOverflow = ui.verticalOverflow; + + if( isComponentWide && !ui.resizeTextForBestFit ) { ui.horizontalOverflow = HorizontalWrapMode.Wrap; - } + ui.verticalOverflow = VerticalWrapMode.Overflow; - _reset = g => - { - var gui = (Text)g; - gui.horizontalOverflow = originalHorizontalOverflow; - }; + if( _unresize == null ) + { + _unresize = g => + { + var gui = (Text)g; + gui.horizontalOverflow = originalHorizontalOverflow; + gui.verticalOverflow = originalVerticalOverflow; + }; + } + } } else { @@ -72,20 +111,25 @@ public void ResizeUI( object graphic ) type.GetProperty( MultiLinePropertyName )?.GetSetMethod()?.Invoke( graphic, new object[] { true } ); type.GetProperty( OverflowMethodPropertyName )?.GetSetMethod()?.Invoke( graphic, new object[] { 0 } ); - _reset = g => + if( _unresize == null ) { - var gtype = g.GetType(); - gtype.GetProperty( MultiLinePropertyName )?.GetSetMethod()?.Invoke( g, new object[] { originalMultiLine } ); - gtype.GetProperty( OverflowMethodPropertyName )?.GetSetMethod()?.Invoke( g, new object[] { originalOverflowMethod } ); - }; + _unresize = g => + { + var gtype = g.GetType(); + gtype.GetProperty( MultiLinePropertyName )?.GetSetMethod()?.Invoke( g, new object[] { originalMultiLine } ); + gtype.GetProperty( OverflowMethodPropertyName )?.GetSetMethod()?.Invoke( g, new object[] { originalOverflowMethod } ); + }; + } } } } public void UnresizeUI( object graphic ) { - _reset?.Invoke( graphic ); - _reset = null; + if( graphic == null ) return; + + _unresize?.Invoke( graphic ); + _unresize = null; } public TranslationInfo Reset( string newText ) diff --git a/src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs b/src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs index 88d09f64..5bfcb21a 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs @@ -5,38 +5,88 @@ using System.Text; using UnityEngine.UI; using XUnity.AutoTranslator.Plugin.Core.Extensions; +using XUnity.AutoTranslator.Plugin.Core.Parsing; namespace XUnity.AutoTranslator.Plugin.Core { public class TranslationJob { - public TranslationJob( TranslationKeys key ) + public TranslationJob( TranslationKey key ) { - Keys = key; + Key = key; Components = new List(); + OriginalSources = new HashSet(); + Contexts = new HashSet(); } + public HashSet Contexts { get; private set; } + public List Components { get; private set; } - - public TranslationKeys Keys { get; private set; } + + public HashSet OriginalSources { get; private set; } + + public TranslationKey Key { get; private set; } public string TranslatedText { get; set; } - public bool AnyComponentsStillHasOriginalUntranslatedText() + public TranslationJobState State { get; set; } + + public bool AnyComponentsStillHasOriginalUntranslatedTextOrContextual() { - if( Components.Count == 0 ) return true; // we do not know + if( Components.Count == 0 || Contexts.Count > 0 ) return true; // we do not know - foreach( var component in Components ) + for( int i = Components.Count - 1 ; i >= 0 ; i-- ) { - var text = component.GetText().Trim(); - if( text == Keys.OriginalKey ) + var component = Components[ i ]; + try + { + var text = component.GetText().TrimIfConfigured(); + if( text == Key.OriginalText ) + { + return true; + } + } + catch( NullReferenceException ) { - return true; + // might fail if compoent is no longer associated to game + Components.RemoveAt( i ); } } return false; } + + public void Associate( TranslationContext context ) + { + if( context != null ) + { + Contexts.Add( context ); + context.Jobs.Add( this ); + } + } + } + + public enum TranslationJobState + { + RunningOrQueued, + Succeeded, + Failed + } + + public class TranslationContext + { + public TranslationContext( object component, ParserResult result ) + { + Jobs = new HashSet(); + Component = component; + Result = result; + } + + public ParserResult Result { get; private set; } + + public HashSet Jobs { get; private set; } + + public object Component { get; private set; } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/TranslationKey.cs b/src/XUnity.AutoTranslator.Plugin.Core/TranslationKey.cs new file mode 100644 index 00000000..31f43da0 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/TranslationKey.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public struct TranslationKey + { + public TranslationKey( object ui, string key, bool templatizeByNumbers, bool neverRemoveWhitespace = false ) + { + OriginalText = key; + + if( !neverRemoveWhitespace + && ( ( Settings.IgnoreWhitespaceInDialogue && key.Length > Settings.MinDialogueChars ) || ( Settings.IgnoreWhitespaceInNGUI && ui.IsNGUI() ) ) ) + { + RelevantText = key.RemoveWhitespaceAndNewlines(); + } + else + { + RelevantText = key; + } + + if( templatizeByNumbers ) + { + TemplatedText = RelevantText.TemplatizeByNumbers(); + } + else + { + TemplatedText = null; + } + } + + public TemplatedString TemplatedText { get; } + + public string RelevantText { get; } + + public string OriginalText { get; set; } + + public string GetDictionaryLookupKey() + { + if( TemplatedText != null ) + { + return TemplatedText.Template; + } + return RelevantText; + } + + public string Untemplate( string text ) + { + if( TemplatedText != null ) + { + return TemplatedText.Untemplate( text ); + } + + return text; + } + + public string RepairTemplate( string text ) + { + if( TemplatedText != null ) + { + return TemplatedText.RepairTemplate( text ); + } + + return text; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/TranslationKeys.cs b/src/XUnity.AutoTranslator.Plugin.Core/TranslationKeys.cs deleted file mode 100644 index b6ac2db8..00000000 --- a/src/XUnity.AutoTranslator.Plugin.Core/TranslationKeys.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using XUnity.AutoTranslator.Plugin.Core.Configuration; -using XUnity.AutoTranslator.Plugin.Core.Extensions; - -namespace XUnity.AutoTranslator.Plugin.Core -{ - public struct TranslationKeys - { - public TranslationKeys( string key ) - { - OriginalKey = key; - DialogueKey = key.RemoveWhitespace(); - } - - public string OriginalKey { get; } - - public string DialogueKey { get; } - - public string ForcedRelevantKey => IsDialogue ? DialogueKey : OriginalKey; - - public string RelevantKey => IsDialogue && Settings.IgnoreWhitespaceInDialogue ? DialogueKey : OriginalKey; - - public bool IsDialogue => OriginalKey.Length > Settings.MinDialogueChars; - } -} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Translations/StaticTranslations.txt b/src/XUnity.AutoTranslator.Plugin.Core/Translations/StaticTranslations.txt new file mode 100644 index 00000000..e82afc91 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Translations/StaticTranslations.txt @@ -0,0 +1,10463 @@ +【アイシャドウ】カラー=[Eye Shadow] Color +【アクセサリ(スロット01)】カラー=[Accessory 01] Color +【アクセサリ(スロット01)】ツヤの色=[Accessory 01] Shine Color +【アクセサリ(スロット02)】カラー=[Accessory 02] Color +【アクセサリ(スロット02)】ツヤの色=[Accessory 02] Shine Color +【アクセサリ(スロット03)】カラー=[Accessory 03] Color +【アクセサリ(スロット03)】ツヤの色=[Accessory 03] Shine Color +【アクセサリ(スロット04)】カラー=[Accessory 04] Color +【アクセサリ(スロット04)】ツヤの色=[Accessory 04] Shine Color +【アクセサリ(スロット05)】カラー=[Accessory 05] Color +【アクセサリ(スロット05)】ツヤの色=[Accessory 05] Shine Color +【アクセサリ(スロット06)】カラー=[Accessory 06] Color +【アクセサリ(スロット06)】ツヤの色=[Accessory 06] Shine Color +【アクセサリ(スロット07)】カラー=[Accessory 07] Color +【アクセサリ(スロット07)】ツヤの色=[Accessory 07] Shine Color +【アクセサリ(スロット08)】カラー=[Accessory 08] Color +【アクセサリ(スロット08)】ツヤの色=[Accessory 08] Shine Color +【アクセサリ(スロット09)】カラー=[Accessory 09] Color +【アクセサリ(スロット09)】ツヤの色=[Accessory 09] Shine Color +【アクセサリ(スロット10)】カラー=[Accessory 10] Color +【アクセサリ(スロット10)】ツヤの色=[Accessory 10] Shine Color +【アンダーヘア】カラー=[Pubic Hair] Color +【アンダーヘア】ツヤの色=[Pubic Hair] Shine Color +【ショーツ】カラー=[Panties] Color +【セット髪】カラー=[Hair Set] Color +【セット髪】ツヤの色=[Hair Set] Shine Color +【タトゥー(体)】カラー=[Tattoo] Color +【タトゥー(顔)】カラー=[Tattoo] Color +【チーク】カラー=[Cheeks] Color +【トップス(水着用)】カラー=[Tops Swimwear] Color +【トップス(水着用)】ツヤの色=[Tops Swimwear] Shine Color +【トップス】カラー=[Tops] Color +【トップス】ツヤの色=[Tops] Shine Color +【ハイライト】カラー=[Highlights] Color +【ハイライト】ツヤの色=[Highlights] Shine Color +【パンスト】カラー=[Pantyhose] Color +【パンスト】ツヤの色=[Pantyhose] Shine Color +【ヒゲ】カラー=[Beard] Color +【ブラ】カラー=[Bra] Color +【ホクロ】カラー=[Mole] Color +【ボトムス(水着用)】カラー=[Bottoms Swimwear] Color +【ボトムス(水着用)】ツヤの色=[Bottoms Swimwear] Shine Color +【ボトムス】カラー=[Bottoms] Color +【ボトムス】ツヤの色=[Bottoms] Shine Color +【リップ】カラー=[Lips] Color +【乳首】カラー=[Nipple] Color +【乳首】ツヤの色=[Nipple] Shine Color +【前髪】カラー=[Bangs] Color +【前髪】ツヤの色=[Bangs] Shine Color +【右目】カラー=[Right Eye] Color +【右目】ツヤの色=[Right Eye] Shine Color +【小美】岩石A1=【小美】 Rock A1 +【小美】岩石A2=【小美】 Rock A2 +【小美】拱形石门=【小美】 Stone Archway +【小美】椅子=【小美】 Chair +【小美】欧式长椅=【小美】 European-style long Chair +【小美】气垫船=【小美】 Pool Float +【小美】泳圈=【小美】 Swim Ring +【小美】玩具喵=【小美】 Toy Box +【小美】石板路=【小美】 Stone Road 01 +【小美】石板路02=【小美】 Stone Road 02 +【小美】石板路03=【小美】 Stone Road 03 +【小美】草地A1=【小美】 Grassland +【左目】カラー=[Left Eye] Color +【左目】ツヤの色=[Left Eye] Shine Color +【後ろ髪】カラー=[Back Hair] Color +【後ろ髪】ツヤの色=[Back Hair] Shine Color +【手袋】カラー=[Gloves] Color +【手袋】ツヤの色=[Gloves] Shine Color +【日焼け跡】カラー=[Tan] Color +【服】カラー=[Clothes] Color +【横髪】カラー=[Side Hair] Color +【横髪】ツヤの色=[Side Hair] Shine Color +【水着】カラー=[Swimsuit] Color +【水着】ツヤの色=[Swimsuit] Shine Color +【爪】カラー=[Fingernail] Color +【爪】ツヤの色=[Fingernail] Shine Color +【白目】カラー=[Eye Whites] Color +【白目】ツヤの色=[Eye Whites] Shine Color +【眉毛】カラー=[Eyebrows] Color +【眉毛】ツヤの色=[Eyebrows] Shine Color +【睫毛】カラー=[Eyelashes] Color +【睫毛】ツヤの色=[Eyelashes] Shine Color +【肌】カラー=[Skin] Color +【肌】ツヤの色=[Skin] Shine Color +【靴】カラー=[Shoes] Color +【靴下】カラー=[Socks] Color +【髪】カラー=[Hair] Color +【髪飾り】カラー=[Hair Ornament] Color +【髪飾り】ツヤの色=[Hair Ornament] Shine Color +<アップローダーサービス規約>= +▲昇順=▲Asc +▼降順=▼Desc +・アナルを拒否しない?=Anal Okay? +・キスを拒否しない?=Kisses Okay? +・ゴム付けなくてもOK?=Condomless Okay? +・性感帯=Ero. Zone +・性格=Personality +・激しい愛撫を拒否しない?=Groping Okay? +・電マを拒否しない?=Toys Okay? +※学生証画像及びカード画像を撮影=※ You can't save the card without taking +00:無表情=00: expressionless +01:喜び=01: Pleased +01:律子紐リボン(色)=01: Ribbon string ribbon (color) +01なし=01 None +02:なし=02: None +02:照れ=02: Shy +02:笑顔=02: Smile +02なし=02 None +03:なし=03: None +03:笑み=03: Smiling +03:苦笑い=03: bitter smile +03なし=03 None +04:なし=04: None +04:ニヤケ=04: Niyake +04:笑顔=04: Smiling +04なし=04 None +05:ドヤ顔=05: Doya face +05:なし=05: None +05:苦笑い=05: Bitter smile +05なし=05 None +06:なし=06: None +06:ニヤケ=06: Suprised +06:驚き=06: Surprise +06なし=06 None +07:ドヤ顔=07: Serious +07:なし=07: None +07:真剣=07: Seriousness +07なし=07 None +08:キメ顔=08: Smug +08:なし=08: None +08:企み=08: Smug +08なし=08 None +09:ツン=09: Tsun +09:なし=09: None +09:自慢顔=09: Boasting +09なし=09 None +0人=0 +10:ウィンク左=10: Wink left +10:なし=10: None +10:不機嫌=10: Cheerful +10なし=10 None +10人=10 +11:ウィンク右=11: Wink right +11:怒り=11: Anger +11人=11 +12:激怒=12: Fury +12:眩しい左=12: Wink Alt left +12人=12 +13:困り=13: Embarrassment +13:眩しい右=13: Wink Alt right +13人=13 +14:悲しい=14: Sad +14:細目=14: Slightly Closed +14人=14 +15:ジト目=15: Slightly Closed Alt +15:大泣き=15: Big crying +15人=15 +16:痛がり=16: Pain +16:見下し=16: Sad +16人=16 +17:呆れ=17: Shocked +17:食いしばり=17: Clenching +17人=17 +18:がっかり=18: Disappointed +18:叫び=18: Scream +18人=18 +19:驚き=19: Surprised +19人=19 +1F女子トイレ=1st Floor Girls' Bathroom +1カメ=Cam 1 +1人=1 +1人用テーブル=1 person table +1人目の視線をカメラに向ける=Player Looks At Camera +1人目の首をカメラに向ける=Player's Head Aims At Camera +1号ヒーローショルダー右用=No. 1 hero shoulder right use +1号ヒーローショルダー左用=No. 1 hero shoulder left use +1号ヒーロースーツ=No. 1 Hero Suit +1号ヒーローヘッド(編集不可)=No. 1 hero head (not editable) +20:真剣=20: Seriously +20人=20 +21:考え=21: Thinking +21人=21 +22:アヘD=22: Ah D +22:企み=22: PTSD +22人=22 +23:ツン=23: Staring +23人=23 +24:ふくれ=24: blister +24:不機嫌=24: Angry +24人=24 +25:おちょぼ口=25: Okobuchi +25:怒り=25: Anger +25人=25 +26:口笛=26: Whistle +26:激怒=26: Fury +26人=26 +27:困り=27: Embarrassment +27人=27 +28:悲しい=28: Sad +28人=28 +29:大泣き=29: Crying +29人=29 +2D効果=2D Effects +2F女子トイレ=2nd Floor Girls' Bathroom +2カメ=Cam 2 +2人=2 +2人目の視線をカメラに向ける=Partner Looks At Camera +2人目の首をカメラに向ける=Partner's Head Aims At Camera +2号ヒーローショルダー右用=No. 2 hero shoulder right use +2号ヒーローショルダー左用=No. 2 hero shoulder left use +2号ヒーロースーツ=No. 2 Hero Suit +2号ヒーローヘッド(編集不可)=No. 2 hero head (not editable) +2穴バイブ=2 Hole Vibe +2連装砲台の模型=Twin Gun Mount Model +2連鞘刀=Twin Sheathed Swords +30:痛がり=30: Pain +30人=30 +31:激痛=31: Painful pain +31人=31 +32:歪み左=32: Distortion left +32人=32 +33:歪み右=33: Distortion right +33:舌出しE=33: Tongue out E +33人=33 +34:恥ずかし=34: Shyness +34人=34 +35:感じ=35: Feeling +35人=35 +36:うっとり=36: Enchantment +36人=36 +37人=37 +38人=38 +3Dサウンド=3D sound +3Dマップ=3D Map +3Dマップ一覧=3D Maps +3D簡易=Simple 3D +3D詳細=Fancy 3D +3F女子トイレ=3rd Floor Girls' Bathroom +3P(抵抗)=3P (resistance) +3P(脱力)=3P (weakness) +3P(豹変)=3P (reversal change) +3P男1(抵抗)=3P man 1 (resistance) +3P男1(脱力)=3P man 1 (weakness) +3P男1(豹変)=3P man 1 (reversal change) +3P男2(抵抗)=3P man 2 (resistance) +3P男2(脱力)=3P man 2 (weakness) +3P男2(豹変)=3P male 2 (reversal change) +3カメ=Cam 3 +3ポイント=Three-Jewel Necklace +3人=3 +3連ハートの指輪=Ring of triple hearts +4/1圆线(粉)=1/4 Curved Wire (Pink) +4/1圆线(黑)=1/4 Curved Wire (Black) +4P奉仕=4P service +4P奉仕男1=4P Service Male 1 +4P奉仕男2=4P service man 2 +4P奉仕男3=4P Service Male 3 +4P挿入(抵抗)=4P Insertion (resistance) +4P挿入(脱力)=4P insertion (weakness) +4P挿入(豹変)=4P insertion (change of leaves) +4P挿入男1(抵抗)=4P insertion man 1 (resistance) +4P挿入男1(脱力)=4P insertion man 1 (weakness) +4P挿入男1(豹変)=4P insertion man 1 (reversal change) +4P挿入男2(抵抗)=4P insertion man 2 (resistance) +4P挿入男2(脱力)=4P insertion man 2 (weakness) +4P挿入男2(豹変)=4P Insertion Man 2 (Screen Change) +4P挿入男3(抵抗)=4P insertion man 3 (resistance) +4P挿入男3(脱力)=4P insertion man 3 (weakness) +4P挿入男3(豹変)=4P inserting man 3 (birch change) +4カメ=Cam 4 +4人=4 +4輪バギー=Quad Bike +595前輪=595 Front Wheel +595後輪=595 Rear Wheel +5P(抵抗)=5P (resistance) +5P(脱力)=5P (weakness) +5P(豹変)=5P (change to the front) +5P男1(抵抗)=5P man 1 (resistance) +5P男1(脱力)=5P man 1 (weakness) +5P男1(豹変)=5P Man 1 (reversal change) +5P男2(抵抗)=5P man 2 (resistance) +5P男2(脱力)=5P man 2 (weakness) +5P男2(豹変)=5P Male 2 (Ranged) +5P男3(抵抗)=5P man 3 (resistance) +5P男3(脱力)=5P man 3 (weakness) +5P男3(豹変)=5P Male 3 (Ranged change) +5P男4(抵抗)=5P man 4 (resistance) +5P男4(脱力)=5P man 4 (weakness) +5P男4(豹変)=5P Male 4 (reversal change) +5カメ=Cam 5 +5人=5 +64分け(右)=64 division (right) +64分けサイド内巻き=64 divide inside side winding +6人=6 +7人=7 +8人=8 +9人=9 +AB型=Type AB +AI傾向=AI Pattern +AVコンポ=AV component +AVコンポ銀=AV Component (Silver) +AVコンポ黒=AV Component (Black) +Aタイプ01=A - Type 01 +Aタイプ02=A - Type 02 +Aタイプ03=A - Type 03 +Aタイプ04=A - Type 04 +Aタイプ05=A - Type 05 +Aタイプ06=A - Type 06 +Aタイプ07=A - Type 07 +Aタイプ08=A - Type 08 +Aタイプ09=A - Type 09 +Aタイプ1=A - Type 1 +Aタイプ10=A - Type 10 +Aタイプ11=A - Type 11 +Aタイプ12=A - Type 12 +Aタイプ13=A - Type 13 +Aタイプ14=A - Type 14 +Aタイプ15=A - Type 15 +Aタイプ16=A - Type 16 +Aタイプ17=A - Type 17 +Aタイプ18=A - Type 18 +Aタイプ19=A - Type 19 +Aタイプ2=A - Type 2 +Aタイプ20=A - Type 20 +Aタイプ21=A - Type 21 +Aタイプ22=A - Type 22 +Aタイプ3=A - Type 3 +A型=Type A +BGM音量=BGM volume +Bタイプ01=B - Type 01 +Bタイプ02=B - Type 02 +Bタイプ03=B - Type 03 +Bタイプ04=B - Type 04 +Bタイプ05=B - Type 05 +Bタイプ06=B - Type 06 +Bタイプ07=B - Type 07 +Bタイプ1=B - Type 1 +B型=Type B +C4-4(引爆器)=C4-4 (Detonator) +C4-4(炸弹)=C4-4 (Bomb) +C4定时炸弹=Time Bomb +CAキャップ(色)=CA cap (color) +CAスカーフ(色)=CA scarf (color) +DW6甄姬外套=Zhenji's Top (DW6) +DW6甄姬裙=Zhenji's Bottoms (DW6) +Eフィニ=E Fin +FKアイテム=FK Items +FKアナルビーズ1=FK Anal Beads 1 +FKアナルビーズ2=FK Anal Beads 2 +FKアナルビーズ3=FK Anal Beads 3 +FKサキュバスの羽根右=FK Succubus Wing Right +FKサキュバスの羽根左=FK Succubus Wing Left +FKひも=FK String +FKフードマント=FK Hooded Cloak +FKママチャリ=FK Retro Bicycle +FKメタルひも=FK Metal String +FK和柄リボン=FK Japanese Pattern Ribbon +FK忍びマフラー=FK Shinobi Muffler +FK拘束用首輪=FK Restraint Collar +FK紙=FK Paper +FK羽根右=FK Angel Wing Right +FK羽根左=FK Angel Wing Left +FK触手1=FK Tentacle 1 +FK触手2=FK Tentacle 2 +FK軸=FK Shaft +FK鎖=FK Chain +FK関節=FK Joint +FPSの表示設定を変更します=Change display setting of FPS +FPS表示=FPS indication +Fフィニ=F Fin +GPアーム基部=GP Arm Base +GPベース=GP Base +Gスポット攻め=G-Spot Attacking +HL_アナルフック=HL_Anal hook +HL_アフターバーナー=HL Afterburner +HL_インターセプター=HL Interceptor +HL_カップ麺=HL Noodle Cup +HL_サンタ帽=HL Santa Cap +HL_スクーター=HL Scooter +HL_ビートル=HL VW Beetle +HL_フェンス=HL Fence +HL_割りばし=HL Breakfast +HL_双頭ディルド=HL_Double-headed Dildo +HL_地下線路=HL Animated Train Tunnel +HL_山の道路=HL Mountain Road +HL_湯気っぽい物=HL Surface Steam (Big) +HL_湯気っぽい物_中=HL Rising Steam (Mid) +HL_火花=HL Spark +HL_白煙=HL White Smoke +HL_縄=HL_Rope +HL_車の白煙=HL Car Exhaust Fumes +HL_道路(片2)=HL Road (Piece 2) +HL_雨=HL Rain +HL_雪=HL Snow +HL_電柱(片2用)=HL Utility Pole (For Piece 2) +HL_黒煙=HL Black Smoke +Hアイテム=H-Items +Hアニメ=H Animation +Hアニメコントローラー=H-Animation Controller +Hアニメリスト=H-Animation List +Hキャラカスタム=H Character Custom +Hシーン(Hなムード)=H-Scene (H-Mode) +Hシーン(穏やか)=H-Scene (Gentle) +Hシーン(覗き)=H-Scene (Peeping) +Hシーンを終了しますか?=Do you want to end the H scene? +Hしたい=Do H +Hするキャラを選ぶ=Start H-mode +Hに抵抗がある=Hates H +H力=H power +H呼吸奉仕不慣れ=Inexperienced H-Service Breathing +H呼吸奉仕慣れ=Experienced H-Service Breathing +H呼吸奉仕淫乱=Lewd H-Service Breathing +H呼吸愛撫不慣れ=Inexperienced H-Caress Breathing +H呼吸愛撫慣れ=Experienced H-Caress Breathing +H呼吸愛撫淫乱=Lewd H-Caress Breathing +H呼吸挿入不慣れ=Inexperienced H-Insertion Breathing +H呼吸挿入慣れ=Experienced H-Insertion Breathing +H呼吸挿入淫乱=Lewd H-Insertion Breathing +H回数=H count +H奉仕=H Service +H属性=H-Traits +H度=H level +H愛撫=H-Caressing +H抵抗1=H resistor 1 +H抵抗2=H resistance 2 +H抵抗3=H resistor 3 +H挿入=H Insertion +H段階=H-Level +H汎用=H General +H特殊=Special H +H終了=End H-Scene +H経験=H experience +H経験値n倍=H-Experience Multiplier +H行為の継続=H Continuation of action +H表情=HLook +H複数=H Multiple +H豹変1=H Change 1 +H豹変2=H change 2 +H豹変3=H change 3 +H追加①=H Addition ① +H開始=Start H Scene +IKコントローラー=IK Controller +IKターゲットの大きさ=IK Target Size +IKターゲット表示=IK Target Display +IKポーズ=IK Pose +IW咖啡杯(含咖啡)=[IIlus] Cup (Inclusive) +IW咖啡杯(空)=[IIlus] Cup (Sky) +IW購物袋(附菜)=[IIlus] Shopping Bag +IW餐點組1=[IIlus] Item Group 1 +Lv0フェラチオ=Lv 0 Blowjob +Lv0後背位=Lv 0 Doggy position +Lv1フェラチオ=Lv 1 Blowjob +Lv1後背位=Lv1 Doggy position +Lv2フェラチオ=Lv 2 blowjob +Lv2後背位=Lv 2 Doggy position +Lv3フェラチオ=Lv 3 blowjob +L字カウンター=L character counter +M4黑龙=CF M4 +MAP特殊=Map special +MAP特殊H=MAP Special H +Mコート=M Coat +M字バング=M-Shaped Bangs +M字バングストレート(右)=M-Shaped Straight Bangs (R) +M字バングストレート(左)=M-Shaped Straight Bangs (L) +O型=Type O +P(破壊)抜刀=Pirotess (Destruction) Sword +P(破壊)標準=Pirotess (Destruction) Standard +P(脱ぎ)標準=Pirotess (Undress) Standard +PCデスク=PC desk +PH_セクシーボンデージ=PH_ sexy bondage +PH_主人公=PH_ Takeru character +PH_律子=PH_ Ritsuko +PH_明子=PH_ Akiko +PH_競泳ハーフスパッツ=PH_ Swimming Half Spats +PH_雪子=PH_ Yuko +PH首手枷=PH neck cushion +Pスカート(橙)=P skirt (orange) +Pスカート(灰)=P skirt (ash) +Pスカート(紺)=P skirt (navy) +Pスカートチェック(灰)=P skirt check (ash) +Pスカートチェック(青)=P skirt check (blue) +Q猪=Pig 2 +SBS警備員腕章(色)=SBS security guard Armband (color) +SE音量=Game Sound FX +SL_機関車=SL_Locomotive +SMギロチン(ハニー)=SM Guillotine (Honey) +SMギロチン(ハニー)=SM Guillotine (Honey) +SM三角木馬(ハニー)=SM Triangular Horse (Honey) +SM三角木馬(ハニー)=SM Triangular Horse (Honey) +SM固定ギロチン(ハニー)=SM Fixed Guillotine (Honey) +SM固定ギロチン(ハニー)=SM Fixed Guillotine (Honey) +SM部屋=SM Room +SP_破烂背心=SP_Ripped Vest +SP_高领连衣裙=SP_High Collar Dress +SPループ=SP loop +SSR(周囲の反射)を有効にする=SSR (Screen Space Reflection) +TC洗手台(白)=Zera Sink A +TC洗手台(黑)=Zera Sink B +TH前タイヤ=TH Before Tire +TVセット=TV set +TVセット白=TV Set (White) +TVセット茶=TV Set (Tea) +TVセット黒=TV Set (Black) +Tシャツ(柄A)=T-Shirt (Design A) +Tシャツ(柄B)=T-Shirt (Design B) +Tシャツ(無地)=T-Shirt (Plain) +Tシャツ(白)=T-shirt (white) +Tシャツ(紺)=T-shirt (dark blue) +Tシャツ(色)=T-shirt (color) +Tシャツ(色変え可能)=T-Shirt (Custom Color) +Tシャツ無地(男)=Plain T-Shirt (Male) +Tゾーン強調=T zone emphasis +Tポーズ=T pause +T字剃刀=KC Razor +U型线(粉)=U Shaped Wire (Pink) +U型线(黑)=U Shaped Wire (Black) +U警備=U Security Uniform +Vライン=V line +Vワンピース(色)=V one piece (color) +Vワンピース(色変え可能)=V-Neck One-Piece (Custom Color) +Vワンピース(赤)=V One Piece (Red) +Vワンピース(黄)=V One Piece (Yellow) +V字(キャラ)=V-Mark (Character) +V字(通常)=V-Mark (General) +WSオープンショルダー(色)=WS open shoulder (color) +WSオープンショルダー柄(色)=WS open shoulder pattern (color) +WSスカート(色)=WS skirt (color) +WSスカート柄(色)=WS skirt pattern (color) +Wフェラ=W Fellatio +Wフェラ(拘束)=W Fellatio (restraint) +Wフェラ(男拘束)=W Blow Job (man restraint) +Wフェラ女1=W Fellatio Female 1 +Wフェラ女1(男拘束)=W Blowjob 1 (man restraint) +Wフェラ女2=W Fellatio Female 2 +Wフェラ女2(男拘束)=W Blowjob 2 (man restraint) +X回転=X Rotation +X軸=X +yy-旗袍-中国龙=yy Cheongsam - Chinese Dragon +yy-格子旗袍=yy Checkered Cheongsam +yy-美人鱼=yy - Mermaid +Y回転=Y Rotation +Y軸=Y +Z回転=Z Rotation +アーガイル=Argyle +アーチ=Arch +アーマープレート=Armor Plate +アームリボン右用(色)=Arm ribbon right (color) +アームリボン左用(色)=Arm ribbon for left (color) +アイアンメイデン=Iron Maiden +アイカラー=Eye color +アイシャドウ=Eye Shadow +アイシャドウの種類=Eyeshadow Type +アイシャドウの色=Eye Shadow Color +アイシャドウの設定=Eye Shadow +アイス(ココア)=Ice Cream (Brown) +アイス(バニラ)=Ice Cream (White) +アイス(ミント)=Ice Cream (Green) +アイスクリーム=Ice Cream +アイテム=Items +アイテムFKのカラー設定=Item FK Color Settings +アイテムカラー1=Item Color 1 +アイテムカラー2=Item Color 2 +アイテムカラー3=Item Color 3 +アイテムカラー4=Item Color 4 +アイテムその他=Item Other +アイテムリスト=Item List +アイテム切替=Item switching +アイテム検索=Item Search +アイドル=Idol +アイドルカット(右)=Idol Cut (R) +アイドルカット(左)=Idol Cut (L) +アイドルスカート(色)=Idol skirt (color) +アイドルスカート(色変え可能)=Idol skirt (CC) +アイドルトップス(色)=Idol tops (color) +アイドルトップス(色変え可能)=Idol Top (CC) +アイドルニーソックス=Idol Kneesocks +アイドルに戻す=Default Idol +アイドルパンプス=Idol Pumps +アイドルワンピ=Idol One-Piece +アイドル手袋=Idol Gloves +アイドル服=Idol Outfit +アイドル衣装(赤)=Idol costume (red) +アイドル衣装(青)=Idol costume (blue) +アイドル衣装(黄)=Idol costume (yellow) +アイドル衣装赤=Idol Costume Red +アイドル衣装青=Idol Costume Blue +アイドル衣装黄=Idol Costume Yellow +アイパッチ(色)=Eye patch (color) +アイビー=Ivy +アイビースリーブ=Ivy sleeve +アイビーバイン=Ivey Vin +アイビーホーズ=Ivy Hoes +アイマスク=Eye mask +アイマスク(色)=Eye mask (color) +アイマスク(赤)=Eye mask (red) +アイマスク(黒)=Eye mask (black) +アイライン=Eye line +アイライン01=Eye line 01 +アイライン02=Eye line 02 +アイライン03=Eye line 03 +アイライン04=Eye line 04 +アイライン05=Eye line 05 +アイライン06=Eye line 06 +アイライン07=Eye line 07 +アイライン08=Eye line 08 +アイライン09=Eye line 09 +アイライン10=Eye line 10 +アイライン11=Eye line 11 +アイライン12=Eye line 12 +アイライン13=Eye line 13 +アイライン14=Eye line 14 +アイラインの色=Eyeliner Color +アイライン上の種類=Upper Eyeliner Type +アイライン下の種類=Lower Eyeliner Type +アヴェンタドール=Aventador +アウターの種類=Outerwear Type +アウトドア=Outdoors +アウトラインの幅=Outline Thickness +アウトラインの濃さ=Outline Density +アウトラインの色=Outline Color +アウトラインの色を個別に設定する=Enable Outline Color Adjustment +アクション=Action +アクション1=Action 1 +アクション2=Action 2 +アクセ=Accessories +アクセサリ=Accessory +アクセサリ(手)の種類=Accessory (Hands) Type +アクセサリ(股間)の種類=Accessory (Crotch) Type +アクセサリ(胴)の種類=Accessory (Body) Type +アクセサリ(脚)の種類=Accessory (Legs) Type +アクセサリ(腕)の種類=Accessory (Arms) Type +アクセサリ(腰)の種類=Accessory (Waist) Type +アクセサリ(頭)の種類=Accessory (Head) Type +アクセサリ(顔)の種類=Accessory (Face) Type +アクセサリ(首)の種類=Accessory (Neck) Type +アクセサリ(髪)の種類=Accessory (Hair) Type +アクセサリ:01=Accessory: 01 +アクセサリ01=Accessory 01 +アクセサリ01の設定=Accessory 01 Settings +アクセサリ02=Accessory 02 +アクセサリ02の設定=Accessory 02 Settings +アクセサリ03=Accessory 03 +アクセサリ03の設定=Accessory 03 Settings +アクセサリ04=Accessory 04 +アクセサリ04の設定=Accessory 04 Settings +アクセサリ05=Accessory 05 +アクセサリ05の設定=Accessory 05 Settings +アクセサリ06=Accessory 06 +アクセサリ06の設定=Accessory 06 Settings +アクセサリ07=Accessory 07 +アクセサリ07の設定=Accessory 07 Settings +アクセサリ08=Accessory 08 +アクセサリ08の設定=Accessory 08 Settings +アクセサリ09=Accessory 09 +アクセサリ09の設定=Accessory 09 Settings +アクセサリ10=Accessory 10 +アクセサリ10の設定=Accessory 10 Settings +アクセサリー=Accessory +アクセサリー常時表示=Always Show Accessories +アクセサリー色=Accessory color +アクセサリコピー補助機能=Accessory copy assist function +アクセサリのみチェック=Accesories Only +アクセサリの色を初期に戻す=Reset To Original Color +アクセサリの表示=Show Accessories +アクセサリ設定=Accessories +アクセスロット01=Accessory 01 +アクセスロット02=Accessory 02 +アクセスロット03=Accessory 03 +アクセスロット04=Accessory 04 +アクセスロット05=Accessory 05 +アクセスロット06=Accessory 06 +アクセスロット07=Accessory 07 +アクセスロット08=Accessory 08 +アクセスロット09=Accessory 09 +アクセスロット10=Accessory 10 +アクセのみ=Accessories Only +アクセのみ読込み=Only Accessory +アクティブコーデ=Active Clothes +あくび=Yawning +あぐら1=Sitting Cross-Legged 1 +あぐら2=Sitting Cross-Legged 2 +あご=Jaw +アコーディオンバッグ=Accordion Bag +アザ01=Aza 01 +アザ02=Aza 02 +アザ03=Aza 03 +アザ04=Aza 04 +アザ05=Aza 05 +アザ06=Aza 06 +アザ07=Aza 07 +アサシン=Assassin +アサシンセット=Assassin Set +アサルトライフル=Assault rifle +アサルトライフル(色)=Assault rifle (color) +アシスト=Assist +アシメミディアム=Asymmetric medium +アスファルト床1=Asphalt Floor 1 +アスファルト床2=Asphalt Floor 2 +アスファルト床3=Asphalt Floor 3 +アスファルト床4=Asphalt Floor 4 +アップツイン=High Twintails +アップバング=Upward Swept Bangs +アップポニー=Up pony +アップローダー=Uploader +アップロード=Upload +アップロードする=Upload +アナル=Anus +アナルイレテ=Penetrate (anal) +アナルイレル=Penetrate (anal) +アナルオナニー=Anal Masturbation +アナルオナニー(抵抗)=Anal Masturbation (resistance) +アナルオナニー(脱力)=Anal Masturbation (weakness) +アナルオナニー(豹変)=Anal Masturbation (Ranged) +アナルバイブ=Anal Vibrator +アナルバイブ(ハニー)=Anal Vibrator (Honey) +アナルバイブ(ハニー)=Anal Vibratior (Honey) +アナルバイブ(長)=Anal Vibrator (Long) +アナルバイブ\(棘ボール\)=Anal Vibe (Thorn Ball) +アナルバイブ\(青\)=Anal Vibe (Blue) +アナルバイブ1=Anal Vibe 1 +アナルバイブ2=Anal Vibe 2 +アナルバイブ3=Anal Vibe 3 +アナルバイブ3\(きのこ\)=Anal Vibe (Mushrooms) +アナルバイブ挿入=Anal Vibrator Insertion +アナルビーズ\(ピンク\)=Anal Beads (Pink) +アナルビーズ\(緑\)=Anal Beads (Green) +アナルビーズ\(黒\)=Anal Beads (Black) +アナルビーズ1=Anal Beads 1 +アナルビーズ2=Anal Beads 2 +アナルビーズ3=Anal Beads 3 +アナルを拒否しない?=Won't Refuse Anal Sex? +アナル側位=Anal Spooning +アナル入れてね=Put it in your ass +アナル入れるよ=I'm putting it in your ass +アナル処女=Anal virgin +アナル処女=Anal virgin +アナル壁立ち後背位=Against Wall Anal +アナル女拘束=Anal Woman Restraint +アナル女拘束(脱力)=Anal woman restraint (weakness) +アナル弄り=Anal Fondling +アナル弄り(抵抗)=Anal torture (resistance) +アナル弄り(脱力)=Anal tits (weakness) +アナル弄り(豹変)=Anal finesse (battle change) +アナル後背位=Anal Doggy +アナル後背位(抵抗)=Anal doggy position (resistance) +アナル後背位(脱力)=Anal doggy position (weakness) +アナル後背位(豹変)=Anal doggy position (birth change) +アナル服従=Anal Submission +アナル椅子座=Anal Chair +アナル椅子後背位=Anal Doggy on Chair +アナル正常位=Anal Missionary +アナル正常位(抵抗)=Anal normal position (resistance) +アナル正常位(脱力)=Anal normal position (weakness) +アナル正常位(豹変)=Anal ordinal position (exaggerated change) +アナル背面=Anal Doggy +アナル背面立位=Anal Standing +アナル背面騎乗位=Anal Reverse Cowgirl +アナル背面騎乗位(抵抗)=Anal Rear woman on top posture (resistance) +アナル背面騎乗位(脱力)=Anal Rear woman on top posture (weakness) +アナル背面騎乗位(豹変)=Anal rear back woman on top posture +アナル舐め=Anal Licking +アナル舐め(抵抗)=Ramification (resistance) +アナル舐め(脱力)=Rim Rick (Weakness) +アナル舐め(豹変)=Rim Rick (Ru] Change +アナル逆駅弁=Anal Reverse Standing +アナル逆駅弁(抵抗)=Anal reverse standing valve (resistance) +アナル逆駅弁(脱力)=Anal reverse standing valve (weakness) +アナル逆駅弁(豹変)=Anal Inverse Evolutionary Valve (Screen Change) +アナル道具=Anal Beads +アナル道具(抵抗)=Anal tool (resistance) +アナル道具(脱力)=Anal tool (weakness) +アナル道具(豹変)=Anal tool (change) +アナル非処女=Anal Experienced +アナル非処女=Anal Unmaren +アナル騎乗位=Anal Cowgirl +アナル騎乗位(抵抗)=Anal woman on top posture (resistance) +アナル騎乗位(脱力)=Anal woman on top posture (weakness) +アナル騎乗位(豹変)=Anal woman on top posture +アニメ=Animations +アニメーション=Animation +アニメーション位置参照=Animation Reference +アニメーション操作=Animation Management +アニメコントローラー=Animation Controller +アニメリスト=Animation Lists +アニメ全体速度=Animation Speed +アニメ調頬1=Animation cheek 1 +アニメ調頬2=Animation cheek 2 +アニメ速度=Animation Speed +アバルト595本体=Abarth 595 Body +アビスビール=Abyss Beer +あほ毛=Ahoge +アホ毛(色)=Aho hair (color) +あほ毛A=Ahoge A +あほ毛B=Ahoge B +あり=Show +アルバム=Album +アルファ=Alpha +アレンジおさげ=Arranging pigtails +あわあわ=Bubbles +アンクルソックス=Ankle Socks +アンクレット=Belly Dancer Anklet +あんころ餅=Anshō Rice +アンダースコート=Underskirt Panties +アンダースコート(桃)=Anders Court (peach) +アンダースコート(白)=Anders Court (White) +アンダーヘアの色に合わせる=Match Pubic Hair +アンダーヘアの設定=Pubic Hair +アンダーリム=Under Rim Glasses +アンダーリム(細)=Under Rim Glasses (Narrow) +アンダーリム(色)=Under rim (color) +アンチエイリアスを有効にする=Anti-Aliasing +アンビエントオクルージョン=Ambient Occlusion +アンビエントオクルージョンを有効にする=Enable Ambient Occlusion +あんみつ=Anmitsu +あんみつ用スプーン=Spoon +あ大=Big A +あ小=Small A +いいえ=No +イージス艦本体=Aegis guided missile defense destroyer unit +イカ型ヘッド=Squid Type Head +イカ型ヘッド(2色)=Squid Type Head (2CC) +イカ型ヘッド・反り=Squid Type Head · Flaccid +イカ型ヘッド・反り(2色)=Squid Type Head · Flaccid (2CC) +イカ型ヘッド・巻き=Squid Type Head · Erect +イカ型ヘッド・巻き(2色)=Squid Type Head · Erect (2CC) +イキそうボタン表示(※1)=Show Orgasm Button (※1) +いたずら=Molesting +イチゴ=Strawberries +いちごみるく=Strawberry Milk +いちご大福=Mochi Rice Cake +イナズマ=Inazuma +いぬの着ぐるみ頭=Dog Costume Head +イメージ=Image +イメージエフェクト=Image Effect +イヤホン=Earbuds +イヤリング右=R. Earring +イヤリング左=L. Earring +イルカ=Dolphin +イルカとカラーストーン(緑)=Dolphins and color stones (green) +イルカとカラーストーン(赤)=Dolphins and color stones (red) +イルカビキニ=Dolphin bikini +イルミネータ=Illuminators +イルミネータ基部=Luminator Base +イレテ=Penetrate +イレル=Penetrate +インテリア棚=Interior shelf +インナーの種類=Innerwear Type +インポート=Import +インポートしました=Scene imported. +い大=Big I +い小=Small I +ウィンクL=Winking L +ウィンクR=Winking R +ウイングサークレット(色)=Wing Circlet (color) +ウイングチップ(白)=Wing tip (white) +ウイングチップ(茶)=Wing tip (tea) +ウイングチップ(赤)=Wing tip (red) +ウイングチップ(黄)=Wing tip (yellow) +ウィンク右=Winking R +ウィンク左=Winking L +ウィンドウ=window +ウィンドウ透過率=Window transmittance +ウインドショート(右)=Wind Short (Right) +ウインドショート(左)=Windshort (left) +ウェイトベンチ=Weight Bench +ウェイトラック=Way Track +ウェイトレス=Waitress +ウェイトレス(レトロ)=Waitress (Retro) +ウェイトレスA(カラー)=Waitress A (CC) +ウェイトレスB(カラー)=Waitress B (CC) +ウェイトレスソックス(色)=Waitress socks (color) +ウェイトレスソックス(色変え可能)=Waitress Socks (Custom Color) +ウェイトレスリボン=Waitress ribbon +ウェーキ=Water Movement (For Big Ships) +ウェーブショート=Wavy Short +ウェーブロング=Wave Long +ウエスタンハット=Western hat +ウエスタンブーツ=Western boots +ウエストの位置=Waist Position +ウエストバッグ(紫)=Waist bag (purple) +ウエストバッグ(緑)=Waist bag (green) +ウエストバッグ(黄)=Waist bag (yellow) +ウエストバッグ(黒)=Waist bag (black) +ウエスト位置=Waist Height +ウェディングコルセット=Wedding corset +ウェディングコルセット(色)=Wedding corset (color) +ウェディングコルセット(色変え可能)=Wedding Corset (Custom Color) +ウェディングショート=Wedding Short +ウェディングショート(色)=Wedding short (color) +ウェディングショート(色変え可能)=Wedding Gloves Short (Custom Color) +ウェディングドレス=Wedding dresses +ウェディングドレス(色)=Wedding dress (color) +ウエディングドレス(色変え可能)=Wedding Dress (Custom Color) +ウェディングパンプス(ピンク)=Wedding pumps (pink) +ウェディングパンプス(ブルー)=Wedding pumps (blue) +ウェディングピンク(色)=Wedding pink (color) +ウェディングピンク(色変え可能)=Wedding Pink (Custom Color) +ウェディングブーケ(色)=Wedding bouquet (color) +ウェディングブルー(色)=Wedding Blue (color) +ウェディングブルー(色変え可能)=Wedding Blue (Custom Color) +ウェディングフレアスカート=Wedding flare skirt +ウェディングフレアスカート(色)=Wedding flare skirt (color) +ウェディングレース=Wedding race +ウェディングレース(色)=Wedding race (color) +ウェディングレース(色)=Wedding race (color) +ウェディングレース(色変え可能)=Wedding Lace (Custom Color) +ウェディングレース(色変え可能)=Wedding Lace (Custom Color) +ウェディングロング=Wedding Long +ウェディングロング(色)=Wedding Long (color) +ウェディングロング(色変え可能)=Wedding Gloves Long (Custom Color) +ウェリントン=Wellington Glasses +ウェリントン(色)=Wellington (color) +ウェルカムレイ桃色(色)=Welcome lei peach color (color) +ウェルカムレイ黄色(色)=Welcome lay yellow (color) +ウォーハンマー=Warhammer +ウォーハンマー(色)=Warhammer (color) +ウォレットチェーン=Wallet Chain +うぐいす餅=Ugly Rice Cake +ウクレレ=Ukelele +うさぎの人形=Rabbit Doll +うさぎの着ぐるみ頭=Rabbit Costume Head +ウサギの置物=Rabbit Ornament +ウサギ尻尾=Rabbit Tail +うさ耳パーカー=Rabbit-Ears Parka +うさ耳バンド=Bunny Ears Hairband +うちわ=Hand Fan +ウッドチェア=Wood chair +うつ伏せ=Lie on Front +うどん毛ロング(前)=Udon hair long (front) +うどん毛ロング(後ろ)=Udon hair long (behind) +うなぎ=Eel +うんこ=Literally Shit 1 +うんこ2=Literally Shit 2 +うんこ3=Literally Shit 3 +うんこ4=Literally Shit 4 +うんこ5=Literally Shit 5 +うんこ6=Literally Shit 6 +うんこ7=Literally Shit 7 +うんこ8=Literally Shit 8 +うんこ9=Literally Shit 9 +う大=Big U +う小=Small U +エアコン=Air Conditioner +エアロバイク1=Aero Bike 1 +エアロバイク2=Aero Bike 2 +エウリノームブラッケン=Eurynome Bracken +エキゾチック=Exotic +エキゾチック(色)=Exotic (color) +エキゾチック(色変え可能)=Exotic (Custom Color) +エキゾチックA(色)=Exotic A (color) +エキゾチックA(色変え可能)=Exotic A (Custom Color) +エキゾチックB(色)=Exotic B (color) +エキゾチックB(色変え可能)=Exotic B (Custom Color) +エキゾチックサンダル(金)=Exotic sandals (gold) +エキゾチックサンダル(銀)=Exotic sandal (silver) +エキゾチックニーソ(色)=Exotic Nisso (color) +エキゾチックニーソ(色変え可能)=Exotic Thigh Highs (Custom Color) +エキゾチックネックレス=Exotic Necklace +エキゾチックリング=Exotic ring +エクステ=Extensions +エクステのアウトラインの色=Extension Outline Color +エクステの基本の色=Extension Base Color +エクステの根本の色=Extension Root Color +エクステの毛先の色=Extension Tip Color +エクステの種類=Extension Type +エステ=Beauty +エステベッド=Esthetic Bed +エッチ=H-Scene +エッチA=Explicit A +エッチB=Explicit B +エナジードリンク黒=Monster Energy Drink +エネミーブレイカー=Enemy Breaker +えねみーぶれいかー=EnemiーBureikaー +エピローグ=Epilogue +エフェクト=Effects +エフェクトコントローラー=Effects Controller +エプロン=Apron +エプロン(ピンク)=Apron (Pink) +エプロン(ピンク)=Apron (pink) +エプロン(桃)=Apron (peach) +エリアライトを有効にする=Environmental Light +エリプティカルマシン=Elliptical Machine +エルフっ娘がいい!=Elf Ears +エレガントショーツ=Elegant Panties +エレガントリボン=Elegant Ribbon +エレキギター=Electric Guitar +エンジェル=Angel +エンジェル(色)=Angel (color) +エンシェントロッド=Ancient Rod +エンディング曲アレンジ1=Ending Arrangement 1 +エンディング曲アレンジ2=Ending Arrangement 2 +エントロッド=Entrod +エントロッド(色)=Entrod (color) +エンブレムシール(上)=Seashells (Top) +エンブレムシール(下)=Emblem Seal (Lower) +エンブレムの種類=Emblem Type +エンブレムを選択して下さい=Please Select an Emblem +え大=Big E +え小=Small E +オウムおもちゃ=Parrot Toy +オウムのおもちゃ(赤)=A parrot toy (red) +オウムのおもちゃ(青)=A parrot's toy (blue) +オーディオ=Audio +オーディオ設定=Audio Settings +オートカメラの回転速度=Auto camera rotation speed +オート待ち時間=Auto wait time +オーバーオール(水)=Overalls (water) +オーバーオール(青)=Overalls (blue) +オーバーオール(黄)=Overall (yellow) +オーバル=Oval Glasses +オーバルA=Oval A +オーバルA(色)=Oval A (color) +オーバルB=Oval B +オーバルB(色)=Oval B (color) +オーバルC=Oval C +オーバルC(色)=Oval C (color) +オーバルD=Oval D +オーバルD(色)=Oval D (color) +オーバル腕時計=Oval Wristwatch +オープニング=Opening +オープンフリルビキニ=Open frills Bikini +オープンリングワンピース=Open Ring One Piece +オープンリングワンピース(色)=Open ring one piece (color) +オープンリングワンピース(色変え可能)=Open Ring One-Piece (Custom Color) +オープンレース(色)=Open race (color) +オープンレース(色変え可能)=Open Lace (Custom Color) +オープンレースショーツ=Open Lace Panties +オープンレースブラ=Open Lace Bra +オール=Oar +オールバック=Allback +おかっぱ=Bobbed +おくりもの=Gift +おさげ=Pigtails +おさげリボン=Pigtail ribbon +オシャレする?=Is Fashionable? +オススメ=Recommended +おせち=Osechi +おせち(空)=Osechi Empty +おせち(蓋)=Osechi Fut +おせち皿A=Osechi A +おせち皿B=Osechi B +おせち皿C=Osechi C +オタク女子=Otaku +おたま=Ladle +オタ芸=Otako +おっとり=Gentle +おっぱいスライダー=Breast slider +おでこ=Forehead +おでん串=Oden Skewers +おでん屋台=Oden Stand +おでん皿盛1=Oden Dish 1 +おでん皿盛2=Oden Dish 2 +オナニー=Masturbation +オナホ=Onahole +おにぎり=Rice Ball +おにぎりと皿=Onigiri (Dish) +おにぎり食べかけ=Onigiri (Bite) +オフ=Off +オフィスチェアー=Office Chair +オフィスデスク=Office Desk +オフィスデスク&チェアー=Office Desk & Chair +オフィスデスク&ファックス=Office Desk With Fax +オフィス机1=Office desk 1 +オフィス机2=Office desk 2 +オフィス机3=Office desk 3 +オフィス棚=Office Shelf +オフィス椅子=Office chair +オフィス風シーリングライト=Office Ceiling Light +オブジェ=Objects +オブジェクトの表示タイプ=Display type of object +オブジェクトの設定=Object Settings +オブジェクトの追加位置=Additional position of object +オブジェクト追加時の自動表示=Automatic display when adding objects +オブジェクト追加時の自動選択=Automatic selection when adding objects +オフショルダーフリル(桃)=Off-shoulder frills (peach) +オフショルダーフリル(紫)=Off-shoulder frills (purple) +オフショルダーフリル(黄)=Off-shoulder frills (yellow) +オプション=Options +オプション:上=Option 1 +オプション:下=Option 2 +オプション①を表示=Show Option ① +オプション①表示=Options 1 Display +オプション②を表示=Show Option ② +オプション②表示=Options 2 Display +オプション表示切替=Show Objects +おもちゃ=Sex Toys +オルカパンチャースーツ=Orca puncher suit +オルカパンチャーフット=Orca puncher foot +オルカヘッド=Orca head +オレンジチャイナ=Orange China +オレンジ髪01=Orange hair 01 +オレンジ髪02=Orange hair 02 +オレンジ髪03=Orange hair 03 +オン=On +お団子アレンジ=Dumpling arrangement +お団子シングル=Single Bun +お団子ダブル=Double Bun +お大=Big O +お姉さん座り=Onee-san Sitting +お嬢様=Ojousama +お嬢様ロング=Long Ojousama Braid +お嬢様分け=Ojousama Parted +お小=Small O +お尻=Butt +お尻が敏感=Sensitive Ass +お泊り=Sleeping Over +お猪口=KC Ochoko +お腹アザ=Stomach Aza +お茶をたてる=Performing Tea Ceremony +お茶をたてる待機=About To Perform Tea Ceremony +お茶を飲む=Drinking Tea +お茶を飲む待機=About To Drink Tea +お茶菓子=Tea Cakes +お金持ちの指輪=Diamond Ring +カーゴパンツ=Cargo Pants +カーゴパンツ(緑)=Cargo pants (green) +カーゴパンツ(黒)=Cargo pants (black) +ガーター(ウェディングレース)=Garter (Wedding Race) +ガーター(色)=Garter (color) +ガーター(色変え可能)=Garter (Custom Color) +ガーター(赤)=Garter (red) +ガーター(黒)=Garter (black) +ガーターソックスA=Garter Socks A +ガーターソックスB=Garter Socks B +ガーターニーソックス(色)=Garter thighhighs (color) +ガーターニーソックス(色変え可能)=Garter Thights (Custom Color) +ガーターベルト=Garter Belt +ガーターリング右(色)=Garter ring right (color) +ガーターリング左(色)=Garter ring left (color) +カーディガン=Cardigan +カーディガン(桃)=Cardigan (peach) +カーディガン(色変可)=Cardigan (CC) +カーディガンキャミソール=Cardigan Camisole +カーディガンコーデ=Cardigan Corde- +カーテン1=Curtain 1 +カーテン2=Curtain 2 +ガーデンチェア=Garden chair +ガーデンテーブル=Garden table +カーテンレール1=Curtain Rails 1 +カーテンレール2=Curtain Rails 2 +カーテン桃=Curtain (Peach) +カーテン窓=Curtain Window +カード=Card +ガード・反撃=Guard and Counter +ガードレール=Guardrail +カードをそのままに上書き=Keep picture +カードを撮影して上書き=Retake picture +カード画像=Character Card Picture +カード画像を撮影=Character Card +カーネーション=Carnation +カーブきのこ=Curved Mushroom +ガーリーボブ(前)=Gurley Bob (front) +ガーリーボブ(後ろ)=Girly bob (behind) +カールポニー=Curled Ponytail +カールボブ=Curled Bob +カールロングポニー=Carl Long Pony +カールロングポニーリボン=Carl Long Pony Ribbon +ガイド=Guide +カウガール=Cowgirl +カウガールジャケット=Cowgirl jacket +カウガールジャケット(改=Cowgirl Jacket Revised (CC) +カウガールチャップス=Cowgirl Chaps +カウガール腕巻き=Cowgirl armwound +カウチソファ=Couch +カウボーイハット=Cowboy Hat +カウンター追撃=[Counter] [Pursuit] +カエデ=Maple Tree +カエルさんごみ箱=Frog's Trash +かかとが潰れたローファー=The heel is crushed Loafer +かかと右=Right Heel +かかと左=Left Heel +かき氷の旗=Shaved Ice Banner +かき氷機=Shaved Ice Machine +かご=Basket +カジュアルオールバック=Casual, All Back +カジュアルショート=Casual Short +カスタム=Customizer +カスタムに戻る=Return +カスタムを終了しますか?=Quit Character customizer? +カスタム状態の反映=Reflecting custom state +カスタム終了=Custom close +カセットコンロ=Cassette stove +カタナ=Katana +カチューシャ(色)=Headband (color) +カチューシャカラー=Headband color +ガッカリ縦線=Disappointing Vertical Line +カツカレー=Katsukare +カツサンド=Pork Sandwich +ガッツ=Guts +カットイン=Cut In +カットイン設定=Cutscene settings +カニ=Crab +カニの空き缶=Crab cans empty +カヌー=Canoe +カフェ=Cafe +カフシューズ(白)=Cuff shoes (white) +カフシューズ(茶)=Cuff shoes (brown) +カフシューズ(黄)=Cuff shoes (yellow) +カフシューズ(黒)=Cuff shoes (black) +カフス=Cuffs +カフス右用=Right Cuff +カフス左用=Left Cuff +カプセル(キャラ)=Capsule (Character) +カプセル(通常)=Capsule (General) +カブトムシ=Rhinoceros Beetle +カフブーツ(色)=Cuff boots (color) +カフブーツ(色変え可能)=Cuff Boots (Custom Color) +かぼちゃパンツ(橙)=Pumpkin pants (orange) +かぼちゃパンツ(灰)=Pumpkin pants (ash) +かぼちゃパンツ(黒)=Pumpkin pants (black) +かぼちゃヘッド=Pumpkin head +がまぐち(閉)=Coin Purse (Closed) +がまぐち(開)=Coin Purse (Open) +かまくら=Kamakura (City) +かまぼこ=Kamaboko +ガムテープ=Packing Tape​ +ガムテープ=Packing Tape​ +カメラ=Camera +カメラ(ハニー)=Camera (Honey) +カメラエフェクト=Camera Effects +カメラエフェクトフレーム=Camera effect frame +カメラのズーム速度=Camera zoom speed +カメラの回転速度を設定します=Set camera rotation speed +カメラの注視点の表示を設定します=Set camera focus +カメラの移動速度を設定します=Set camera movement speed +カメラフリー操作=Camera free operation +カメラフリー操作+オート回転=Camera free operation + auto rotation +カメラライト=Camera light +カメラランダムアングル=Camera Random angle +カメラリセット=Center Camera +カメラ初期化判断=Move Camera On Position Change +カメラ撮影オナニー=Camera Shoot Masturbation +カメラ移動速度=Camera Movement Speed +カメラ設定=Camera Settings +カメラ追従=Follow head +カメラ速度=Camera Speed +カメラ速度X軸=Camera X Speed +カメラ速度Y軸=Camera Y Speed +カモメ町(夜)=Example Stage Gulls Town (Night) +カモメ町(昼)=Example Stage Gulls Town (Noon) +カラー=Color +カラー1=Color 1 +カラー①=Color 1 +カラー2=Color 2 +カラー②=Color 2 +カラー3=Color 3 +カラー③=Color 3 +カラー4=Color 4 +カラー④=Color 4 +カラーコーン=Safety Cone +カラーストーンネックレス=Color stone necklace +カラータイルカーペット=Color Tile Carpet +カラーの調整=Color Adjustment +カラーパレット=Color palette +カラーパレットは体験版未実装です。=The color palette is not yet mounted trial version. +カラービキニ(色)=Color bikini (color) +カラービキニ(色変え可能)=Bikini (Custom Color) +カラーブロック(マゼンタ)=Color Block (Magenta) +カラーブロック(桃)=Color Block (Peach) +カラーブロック(橙)=Color Block (Orange) +カラーブロック(水)=Color Block (Water) +カラーブロック(灰)=Color Block (Ash) +カラーブロック(白)=Color Block (White) +カラーブロック(紫)=Color Block (Purple) +カラーブロック(緑)=Color Block (Green) +カラーブロック(群青)=Color Block (Ultramarine) +カラーブロック(茶)=Color Block (Brown) +カラーブロック(赤)=Color Block (Red) +カラーブロック(青)=Color Block (Blue) +カラーブロック(青緑)=Color Block (Blue Green) +カラーブロック(黄)=Color Block (Yellow) +カラーブロック(黄緑)=Color Block (Lime) +カラーブロック(黒)=Color Block (Black) +カラー名=Color name +カラー変更可能=Color changeable +カラー帽子=Colored Hat +カラー設定=Color Settings +からいのは平気?=Okay With Spicy Food? +ガラス・丸=Glass · Round +ガラス・丸(色)=Glass · Circle +ガラス・四角=Glass · Square +ガラス・四角(色)=Glass · Square +ガラスコップ=Glass Cup +ガラスコップ(入)=Glass cup (On) +ガラスコップ(空)=Glass cup (Sky) +ガラスコップ(色)=Glass Cup +ガラスチェア=Glass chair +ガラステーブル(円)=Circular Glass Table +ガラステーブル(四角)=Rectangular Glass Table +ガラステーブル1=Glass table 1 +ガラステーブル2=Glass table 2 +ガラステーブル3=Glass table 3 +ガラステーブル4=Glass table 4 +ガラステーブル茶=Glass Table (Tea) +ガラステーブル黒=Glass Table (Black) +ガラスの靴=Glass Slippers +ガラスの靴(色)=Glass shoes (color) +ガラスの鼻=Glass Nose +ガラス丸テーブル=Glass Round Table +ガラス入り障子=Glass-Paned Paper Door +カラフル浮き輪=Colorful lifting wheel +カルテ=Karte +ガレージ=Garage +ガレージ(空)=Garage (Empty) +カレースプーン=Spoon with Katsukare +カレンダー1=Calendar 1 +カレンダー2=Calendar 2 +ガントレット(色)=Gauntlet (color) +ガントレット(色変え可能)=Gauntlet (Custom Color) +がんも=Tofu +キーパッド=Keypad +キーパッドで快適にプレイいただけます。=You can play comfortably with the keypad. +キー上下反転=Invert up and down keyboard movement direction +キー左右反転=Invert Left and Right keyboard movement direction +キー感度=Key sensitivity +ギザギザ=Jagged +ギザギザあほ毛=Jagged Ahoge +ギザギザあほ毛A=Jagged Ahoge A +ギザギザあほ毛B=Jagged Ahoge B +キス=Kiss +キス(抵抗)=Kiss (resistance) +キス(脱力)=Kiss (weakness) +キス(豹変)=Kiss (reversal) +キスオナニー=Kiss Masturbation +キスに弱い=Weakness to Kisses +キスマーク=Kiss mark +キスラッシュ=Kiss Rush +キスを拒否しない?=Won't Refuse Kisses? +キス反応ループ=Kissing Reaction Loop +キス反応開始=Initial Kiss Reaction +キス座位=Kissing Sitting +ギターケース=Guitar Case +キック=Kick +キツネ尻尾=Fox Tail +キツネ耳=Fox Ears +きなこ餅=Kinako Mochi +キネマ=Kinematics +キノコ=Mushroom +きのこ=Mushroom +きのこヘア=Mushroom +ギミック=Gimmicks +ギャグ=Gag +ギャグボ=Gag ball +ギャグボール=Ballgag +ギャグボール(ベルト付)=Oral Fixation (With Belt) +ギャグボール1=Gag Ball 1 +ギャグボール2=Gag Ball 2 +キャッシュを削除=Empty cache +キャッシュを有効にする=Enable cache +キャッシュ削除=Cache deletion +キャビンアテンダント(色)=Cabin attendant (color) +キャプテンシールド=Captain America Shield +キャミソール=Camisole +キャミソール(灰)=Camisole (ash) +キャミソール(白)=Camisole (white) +キャミソール(黒)=Camisole (black) +キャミソールとショートパンツ=Camisole and shorts +キャラ=Card +キャラFKのカラー設定=Character FK Color Settings +キャラFK設定=Character FK Settings +キャラカスタム=Customizer +キャラカスタム部位の表示=Display of character custom part +キャラがどこを見るかを設定=Set Character gaze +キャラクターの保存=Save Character +キャラクターの削除=Delete Character +キャラクターの融合=Character Fusion +キャラクターの読込み=Load Character +キャラクターを移動=Move Character +キャラクター位置変更=Character position change +キャラクター切り替え=Switch Character +キャラクター状態=Character State Controller +キャラクター画像を変更する=Change the Character Image +キャラコントローラー1=Move Controller 1 +キャラコントローラー2=Move Controller 2 +キャラサンプル=Sample Characters +キャラスタジオロゴ=Character Studio Logo +キャラスタジオ文字のみ白=Words: "Character Studio" (White) +キャラスタジオ文字のみ黒=Words: "Character Studio" (Black) +キャラスタジオ白=Character Studio (White) +キャラスタジオ黒=Character Studio (Black) +キャラセット=Add Character +キャラデータをアップロードしました=Uploading character data.. +キャラデータを追加しました=Downloading character data.. +キャラのポーズを変更=Change Pose +キャラフォルダから=Character Folder +キャラメイク=Character +キャラメイクを終了しますか?=Quit The Character Maker? +キャラメイクを終了する=Exit Character Editor +キャラライト=Character Lighting +キャラリスト=Characterist +キャラリストA=Character A +キャラリストB=Character B +キャラリスト取得中...=Fetching a character list ... +キャラを編集前に戻しますか?=Revert This Character? +キャラ一覧=Select A Character +キャラ保存と削除=Save/Delete Character +キャラ変更=Replace Character +キャラ情報=Character Information +キャラ状態=Character State +キャラ画像を変更しますか?=Change This Character's Picture? +キャラ管理=Character Management +キャラ編集=Edit Char. +キャラ編集を終了しますか?=Quit Editing This Character? +キャラ読込=Characters +キャラ読込み=Load Character +キャラ追加=Add Character +キャラ選択=Character Select +ギャリソンキャップ(色)=Garrison cap (color) +ギャル=Gyaru +キャンセル=Cancel +キャンセル=Cancel +キャンディ=Candy +キャンドル=Candle +キャンプベッド=Camp bed +キャンペーンガール=Campaign girl +キューティーカチューシャ(色)=Cutie headband (color) +キューティーグローブ(色)=Cutie glove (color) +キューティーソックス(色)=Cutie socks (color) +キューティーチョーカー(色)=Cutie choker (color) +キュート=Cute +キュートダンス=Cute Dance +キュートナースキャップ=Cute Nurse Cap +キュートナースシューズ=Cute Nurse Shoes +キュートナース服=Cute Nurse Outfit +キュートパンツ=Cute Pants +キューブ=Cube +キューブ(キャラ)=Cube (Character) +キューブ(通常)=Cube (General) +キュウリ=Cucumber +キュピーン!=Impact! +キュピーン!(色)=Impact! +キュロットスカート=Culotte Skirt +キュロットパンツ(緑)=Culottes pants (green) +キュロットパンツ(茶)=Culottes pants (brown) +キュロットパンツ(黒)=Culottes pants (black) +キョンシーの札=Gyeongsi's bill +キラキラ=Sparkles +ギロチン=Guillotine +ギロチン(ハニー)=Guillotine (Honey) +ギンガムチェック=Gingham Checkered +クーパーS本体=Cooper S Body +クール=Quiet +クールダンス=Cool Dance +クールな女の子と会話=Conversation With Calm Girl +クオリティ設定=Quality setting +クオリティ設定を変更します=Change the quality setting +ククリ刀=Saber +くしゃみ=Sneezing +クスコ=Speculum +くせストレート=Curled Straight +くせっ毛ショート=Short, Curled +くせっ毛ショート前=Short, Curled Bangs +くせっ毛ロング=Curly hair long +クッキー=Cookie +クナイ=Kunai +クナイ(束)=Kunei (bunch) +クナイ(色)=Kunai (color) +くノ一=Kunoichi +くノ一セット=Kunoichi Set +くノ一籠手(色)=Kunoichi Basketball (color) +くノ一籠手(色変え可能)=Kunoichi Kagami (Custom Color) +くノ一肩当て=Kunoichi Shoulderpad +くノ一肩当て(色)=Kunoichi shoulder rest (color) +くノ一肩当て右用=Kunoichi Shoulderpad (Right) +くノ一肩当て左用=Kunoichi Shoulderpad (Left) +くノ一装束(色)=Kunoichi Costume (color) +くノ一装束(色変え可能)=Kunoichi Costume (Custom Color) +くノ一足袋(色)=Kunoichi Tabi (color) +くノ一足袋(色変え可能)=Kunoichi Tabi (Custom Color) +くノ一足防具(色)=Kno-foot foot protector (color) +くノ一足防具(色変え可能)=Kunoichi Shin Armor (Custom Color) +くま=Bear +くまさん台=Table With Bears +くまで=Rake +くまパンツ=Bear Panties +クモ=Spider +クモの巣=Spiderweb +クモの巣柄(色)=Spider's nest pattern (color) +クモの巣柄(色変え可能)=Cobweb Pantyhose (Custom Color) +グラウンド=Sports Ground +クラシカルメイド(色)=Classical maid (color) +クラシカルメイドタイ(色)=Classical Maid Thai (color) +クラス=Class +グラスハート=Glass Heart +グラデーションボーダー=Gradient +グラデーションボブ(前)=Gradation Bob (front) +グラデーションボブ(後ろ)=Gradation Bob (back) +グラニーバッグ=Granny Bag +グラビア=Gravure +グランドピアノ=Piano +クリ=Enlarge Clitoris +クリアセーブデータ=Clear save data +グリーンアクセント=Green Accents +グリーンチャイナ=Green China +クリスタル=Crystal +クリスタル(キャラ)=Diamond (Character) +クリスタル(通常)=Diamond (General) +クリスマスケーキ=Christmas Cake 2 +クリスマスツリー=Christmas Tree +クリックでピストン開始=Click to Start Piston +クリックで上昇ロック=Click to unlock +クリックで上昇解除=Click to release ascending +クリックで再挿入=Click to Reinsert +クリックで愛撫開始=Click to Start Caressing +クリックで挿入=Click to Insert +クリックで編集=Click to edit +クリックで編集します=Click To Edit +クリックピストン=Quick Piston +クリップ=Clip +クリパーツ=Vagina detachable +クルーソックス(折り返し)=Crew Socks (Cuffed) +クルーソックス(栗)=Crew socks (chestnuts) +クルーソックス(白)=Crew socks (white) +クルーソックス(紺)=Crew Socks (Navy) +グループ=Group +グループ:体=Group: Body +グループ:右腕=Group: Right Arm +グループ:右足=Group: Right foot +グループ:左腕=Group: Left Arm +グループ:左足=Group: Left foot +グループ:手=Group: Hands +グループ:股間=Group: Crotch +グループ:胴=Group: Torso +グループ:脚=Group: Legs +グループ:腕=Group: Arms +グループ:腰=Group: Waist +グループ:頭=Group: Head +グループ:顔=Group: Face +グループ:首=Group: Neck +グループ:髪=Group: Hair +グループ分けです。=a whole group of accessories at once. +くるくる=Curled +くるくるあほ毛=Curly Ahoge +くるくるあほ毛A=Curly Ahoge A +くるくるあほ毛B=Curly Ahoge B +ぐるぐる目1=Circle Eyes 1 +ぐるぐる目2=Circle Eyes 2 +ぐるぐる目3=Spiral Eyes +クレイモア=Claymore +クレイモア(色)=Claymore (color) +グレージャケットキャミソール=Gray Jacket Camisole +クレーン車=Crane truck +クレバスアイズ=Crevass eyes +グロー=Glow +グローエフェクト=Glow effect +グローエフェクトを変更します=Change glow effect +クローバー=Club +クローバー(色)=Clover (color) +クロールで泳ぐ=Swimming Front Crawl +クロスショーツ(色)=Cross shorts (color) +クロスショーツ(色変え可能)=Cross (Custom Color) +クロスショート=Cross shorting +クロススラッシュ=Cross Slash +クロススラッシュ×5=Cross Slash x5 +クロスネックレス(色)=Cross Necklace (color) +クロスブラ(色)=Cross-bra (color) +クロスブラ(色変え可能)=Cross (Custom Color) +クロスヘアピン=Cross Hairpin +クロスホルター=Cross Halter +クロスマイクロビキニ(色)=Cross micro bikini (color) +クロスマイクロビキニ(色変え可能)=Cross Micro Bikini (Custom Color) +クワガタ=Stag Beetle +クンニ=Cunnilingus +ゲームSE=Game SFX +ゲームコントローラー=Game Controller +ゲームブース=Game Booth +ゲームをする=Playing Game +ゲームを終了=Quit Game +ゲームを終了します。よろしいですか?=End game, Are you sure? +ゲームを終了しますか?=Quit The Game? +ゲーム世界の色合いの雰囲気を設定します=Set atmosphere of hue of the game world +ゲーム終了=End game +ゲーム設定=Game +ゲーム開始=Start Game +ケバブA=Kebab A +ケバブB=Kebab B +ケバブ串=Kebab Skewers +ケロリン二丁目(夜)=Kerolin (Night) +ケロリン二丁目(昼)=Kerolin (Noon) +けんとうし=Gentoushi +コイカツ=Koikatsu +コイカツ女学園=Koikatsu Girls' Academy +コイカツ女学園学園長=Koikatsu Girls' Academy, Headmistress +コイカツ部=Koikatsu Club +コイカツ部に誘う=Invite to Koikatsu +コイバナ=Love talk +コイン=Coin +コウモリ=Bats +ゴーグル=Goggles +ゴースト=Ghost +コーデ=Clothing +コーディネート=Clothing +コーディネートセット=Clothing Sets +コーディネートタイプ=Uniform Type +コーディネート一覧=Clothing Sets List +コーディネート名=Clothing Set Name +コーディネート名を入力して下さい=Please Enter A Name For The Clothing Set +コート・タンクトップ(橙)=Coat · Tank top (Orange) +コート・タンクトップ(黒)=Coat · Tank top (black) +コーナー机=Corner Desk +コーヒー=Cup Of Coffee +コーヒーはブラック?=Drinks Their Coffee Black? +ゴーヤ=Bitter Gourd +コールドアイズ=Cold Eyes +ゴールドブレスレット=Gold bracelet +コーン=Cone +コーン(キャラ)=Cone (Character) +コーン(通常)=Cone (General) +コーンバー=Cone Bar +コクーンパンツ(橙)=Cocoon pants (orange) +コクーンパンツ(灰)=Cocoon pants (ash) +コクーンパンツ(紺)=Cocoon pants (navy blue) +コクーンパンツ(緑)=Cocoon pants (green) +こける=Rubbing +コスト=Cost +コスモス=Cosmos Flower +コスモス(散)=Cosmos Flower (Scattered) +コスモス(束)=Cosmos Flower (Bunch) +ゴスロリスカート=Gothic lolly skirt +ゴスロリスカート(色)=Gothic lolly skirt (color) +ゴスロリスカート(色変え可能)=Gothic Lolita Skirt (Custom Color) +ゴスロリズボン=Gothry lolly pants +ゴスロリズボン(色)=Gothic lolly pants (color) +ゴスロリズボン(色変え可能)=Gothic Lolita Pants (Custom Color) +ゴスロリトップ(色)=Gothic lolita top (color) +ゴスロリトップ(色変え可能)=Gothic Lolita Top (Custom Color) +ゴスロリハット(色)=Gothic lolita hat (color) +ゴスロリパンプス(色)=Gothic lolly pumps (color) +ゴスロリパンプス(色変え可能)=Gothic Lolita Pumps (Custom Color) +ゴスロリブーツ(色)=Gothic lolita boots (color) +ゴスロリブーツ(色変え可能)=Gothic Lolita Boots (Custom Color) +ゴスロリブローチ(色)=Gothic lolita brooch (color) +ゴスロリ着物=Gothic lady kimono +ゴス着物=Goth kimono +ゴス着物前割れ=Goth kimono front crack +コタツ=Kotatsu +こたつ=[PCM] Kotatsu +こっち=Cam +コップ(水)=Cup (water) +この子をカードに保存する=Save Girl to Card +この席には既に女の子が座っています=A girl already sits in this seat. +この投稿者のキャラをみる=Look at this character's character +この条件で探す=Search +ごはん=Bowl Of Rice +コピー=Copy +コピーする項目を選択して下さい=Select Items to Copy +コピー元=Copy source +コピー元のコーディネート=Uniform Source +コピー元を選択して下さい=Item Source +コピー先=Copy destination +コピー先のコーディネート=Uniform Destination +コピー先を選択して下さい=Item Destination +コピー機=Copy Machine +コミック=Comics +コミュニケーションモード=Communication Mode +ゴミ箱=Trash bin +ゴミ箱1=Garbage Can 1 +ゴミ箱2=Garbage Can 2 +ゴミ箱3=Garbage Can 3 +ゴミ箱4=Garbage Can 4 +ゴミ箱5=Garbage Can 5 +ゴミ箱6=Garbage Can 6 +ゴミ箱茶=Trash (Tea) +ゴミ箱黒=Trash (Black) +ゴミ袋=Garbage Bags +ゴム付けなくてもOK?=Sex Without Condoms Is Okay? +コメント=Comment +コメント(80文字以内)=Comment (within 80 letters) +コメントを入力してください=Please enter comments +コルクサンダル=Cork Sandals +コルクボード=Corkboard +これで保存しますか?=Save this Character? +コロッケ1個=Croquette (1) +コロッケパック入り=Croquette (Packed) +コンクリ地下室=Concrete Basement +コンシェルジュスーツ=Concierge suit +コンシェルジュスカート=Concierge skirt +コンシェルジュスリーブ=Concierge sleeve +コンシェルジュハット=Concierge Hut +コンシェルジュブーツ=Concierge boots +コンセント=Electrical Socket +コンセントコード1=Electrical Cord 1 +コンセントコード2=Electrical Cord 2 +コンセントコード3=Electrical Cord 3 +コンセントコード4=Electrical Cord 4 +コンセントコード5=Electrical Cord 5 +コンティニュー=Continue +コンテナ1=Container 1 +コンテナ2A=Container 2A +コンテナ2B=Container 2B +コントラスト率=Contrast ratio +コントローラー=Controller +コントローラーパッドの表示を変更します=Change display of controller pad +コントロールパッドの表示=Control pad display +こんにゃく=Konjac +コンバットナイフ=Combat Knife +コンビニ=Convenience Store Uniform +コンビニ店員(色)=Convenience store clerk (color) +コンビニ袋=Convenience Store Bag +コンフィグ=Config +コンフィグを開く=Config +コンフィグ依存=From Config +コンフィグ設定=Configuration +ごんぶと=Congratulations +コンポ=Compact Stereo +サーキュレーター=Air Circulator +サーバーへの接続に失敗しました=Failed to connect to server +サーバーをチェックしています=Checking server.. +サーバーをチェックしています.=Checking Server. +サーバーをチェックしています..=Checking Server.. +サーバーをチェックしています...=Checking Server... +サーバーをチェックしています....=Checking Server.... +サーバーをチェックしています.....=Checking Server..... +サーバー接続確認中...=Server connection checking ... +サーフボード=Surfboard +サーベル=Saber- +サイコうさぎ=Psycho Bunny +サイコシャード=NeoZeong Pshard +サイズ=Size +サイドアップ=Side up +サイドアップ(キャップ)=Side-up (cap) +サイドアップ(右)=Side-Up (R) +サイドアップ(左)=Side-Up (L) +サイドカール=Side Curl +サイドテール(右)=Side Tail (R) +サイドテール(左)=Side Tail (L) +サイドベルトスカート(桃)=Side belt skirt (peach) +サイドベルトスカート(水)=Side belt skirt (water) +サイドベルトスカート(青)=Side belt skirt (blue) +サイドベルトスカート(黒)=Side belt skirt (black) +サイドリボンカチューシャ(色)=Side ribbon headband (color) +サイドリボンパンプス=Side-Ribbon Pumps +サイド分け=Side dividing +サイド分けウェーブロング=Side Wave Long +サイド分けミディアム=Medium side divided +サイバーアーム(色変え可能)=Cyber Sleeve (CC) +サイバーグローブ=Cyberglove +サイバーシューズ=Cyber ​​shoes +サイバーシューズ(色変え可能)=Cyber Shoes (CC) +サイバースカート=Cyber ​​skirt +サイバースカート(色変可能)=Cyber Skirt (CC) +サイバートップ(色変え可能)=Cyber Top (CC) +サイバーニーソックス=Cyber ​​Knee socks +サイバーニーソックス(色変え可能)=Cyber Knee Socks (CC) +サイバーブルー=Cyber ​​Blue +サイハイブーツ(色)=Sai high boots (color) +サウンド=Sound +サウンド設定=Sound +サカキ=Sakaki +サキュバス=Succubus +サキュバスグローブ(色)=Succubus glove (color) +サキュバススーツ(色)=Succubus suit (color) +サキュバススーツ(色変え可能)=Succubus Suit (CC) +サキュバススカート(色)=Succubus skirt (color) +サキュバススカート(色変え可能)=Succubus Skirt (CC) +サキュバスセット=Succubus Set +サキュバスネックレス(色)=Succubus necklace (color) +サキュバスの右腕飾り(色)=Succubus' right arm ornament (color) +サキュバスの左腕飾り(色)=Succubus's left arm ornament (color) +サキュバス右腕飾り=Succubus Right Arm Acc +サキュバス左腕飾り=Succubus Left Arm Acc +ザク2足=Zaku 2 Leg +ザクマシンガン=Zaku Machine Gun +サスペンダー=Suspenders +サスペンダーL=Suspenders L +サスペンダーS=Suspenders S +サスペンダースカート(白)=Suspender skirt (white) +サスペンダースカート(赤)=Suspender skirt (red) +サスペンダースカート(青)=Suspender skirt (blue) +サソリ=Scorpion +サッカーゴール=Soccer Goal +サブ=Sub +サブカラー=Sub Color +サブの色=Sub color +サマー=Summer +サマースカート(栗)=Summer skirt (chestnut) +サマースカート(水)=Summer skirt (water) +サマースカート(黒)=Summer skirt (black) +サマーポンチョ(橙)=Summer poncho (orange) +サマーポンチョ(白)=Summer poncho (white) +サマーポンチョ(茶)=Summer poncho (tea) +サムネイルキャッシュサイズ=Thumbnail cache size +サムネイル取得中...=Acquiring thumbnail ... +サラシ=Gauze Bindings +サラダ=Salad +サラダ巻=Sushi Roll +サラマンダー=Salamander +されてない=Not Found +されてる=Found +されるのに弱い=Weak to Caresses +サロペット=Overalls +サングラス=Sunglasses +サングラス(色)=Sunglasses (color) +サンシャフト=Sunshafts +サンセットホテル=Sunset Hotel +サンタ=Santa +サンタジャケット=Santa Jackett +サンタジャケット(色)=Santa Jacket (color) +サンタジャケット(色変え可能)=Santa Jacket (Custom Color) +サンタスカート=Santa skirt +サンタスカート(色)=Santa skirt (color) +サンタスカート(色変え可能)=Santa Skirt (Custom Color) +サンタセット=Santa Set +サンタニーソックス(色)=Santa knee socks (color) +サンタニーソックス(色変え可能)=Santa Knee Socks (Custom Color) +サンタのソリ=Santa Slay +サンタビキニ=Santa bikini +サンタビキニ(色)=Santa bikini (color) +サンタビキニ(色変え可能)=Santa Bikini (Custom Color) +サンタブーツ=Santa boots +サンタブーツ(色)=Santa boots (color) +サンタブーツ(色変え可能)=Santa Boots (Custom Color) +サンタベルブローチ=Santa bell brooch +サンダル=Sandals +サンダル(白)=Sandal (white) +サンダル(黒)=Sandal (black) +サンタ帽子=Santa hat +サンタ帽子(色)=Santa hat (color) +サンタ手袋=Santa gloves +サンタ手袋(色)=Santa gloves (color) +サンタ手袋(色変え可能)=Santa Gloves (Custom Color) +サンタ服=Santa Top +サンドイッチ=Sandwich +サンドイッチ1=Sandwich 1 +サンドイッチ2=Sandwich 2 +サンバイザー=Sun Visor +サンバイザーA(白)=Sun visor A (white) +サンバイザーA(赤)=Sun visor A (red) +サンプル=Sample +サンプル表示=Sample +さんま塩焼単品=Pike Shioyaki (1) +さんま塩焼皿付=Pike Shioyaki (Dish) +シースルーニーソ(栗)=See-through knee (chestnut) +シースルーニーソ(桃)=See-through knee (peach) +シースルーニーソ(黒)=See-through knee (black) +シースルーパレオ=See-Through Pareo +シースルーブラック=See-through black +シースルーレッド=See-through red +シーフ=Thief +しーふ=Shiーfu +シームニーソックス=Seamed Kneesocks +シーン1=Scene 1 +シーン2=Scene 2 +シーン3=Scene 3 +シーン4=Scene 4 +シーン5=Scene 5 +シーンを初期化します。よろしいですか?=The scene will be reset. Are you sure? +シーンを終了しますか?=Do you want to exit? +シーンを終了しますか?ああああ=Do you want to exit? +シーン初期化=Reset Scene +ジェスチャー=Gesture +シェルサンダル=Shell Sandals +ジェントルスーツ(白)=Gentle suit (white) +ジェントルスーツ(黒)=Gentle suit (black) +しきい値=Threshold Level +しきい色=Threshold Color +シグネット本体=Signet Body +ししおどし=Shishi-odoshi +シスターベール=Sister veil +システム=System +システムSE=System SFX +システムキッチン=System Kitchen +システムメニュー=System Menu +システム画面=System Screen +システム音=System +システム音の音量を設定します=Set system sound volume +システム音量=System Sound FX +シダ=Fern +しっぽり=Tender +シデ=Shinto Paper Streamer +シトリースカーフ=Scythe Scarf +シトリーの髪型=Citrine's hairstyle +シトリーの髪型改1=Citrine's Hair Style Improvement 1 +シトリーの髪型改2=Citrine's Hair Style Improvement 2 +ジト目うさぎ=Disgusted Rabbit +しない=No +しないと保存できません。=both a student card and character card picture. +シナンジュBP=Sinanju BP +シナンジュRSR=Sinanju RSR +シナンジュSSL=Sinanju SSL +シナンジュSSR=Sinanju SSR +シナンジュTP=Sinanju TP +シマウマ=Zebra Stripes +ジャージ(スカート)=Jersey (Over Skirt) +ジャージ(フィット)=Jersey (To Waist) +ジャージ(灰)=Jersey (ash) +ジャージ(緑)=Jersey (green) +ジャージ(赤)=Jersey (red) +ジャージ(青)=Jersey (blue) +ジャージ前開き=Open Jersey +シャーペン=Mechanical Pencil +シャイニング・フレア=Shining Flare +しゃがみ=Taking A Knee +しゃがみ1=Squatting 1 +しゃがみ1=Squat Down 1 +しゃがみ2=Squatting 2 +しゃがみ2=Squat Down 2 +しゃがみ3=Squatting 3 +しゃがみ歩き=Crouch-Walking +シャギー=Shaggy +シャギーショート=Shaggy Short +シャギーセミショート=Shaggy Semi Short +シャギーロング=Shaggy Long +ジャケットキャミソール(灰)=Jacket camisole (ash) +ジャケットキャミソール(灰)=Jacket camisole (ash) +ジャケットキャミソール(白)=Jacket camisole (white) +ジャケットキャミソール(黒)=Jacket Camisole (black) +ジャケットキャミソール(黒)=Jacket Camisole (black) +ジャケットタイプ=Jacket Type +ジャケットタンクトップ=Jacket And Tank Top +シャチフロート=Killer whale +シャツカーディガン(橙)=Shirt cardigan (orange) +シャツカーディガン(紺)=Shirt cardigan (dark blue) +シャツカーディガン(赤)=Shirt cardigan (red) +シャッター街=Dead Mall Style 2 +シャッター街店舗=Dead Mall Apend +シャツベストストライプ(色)=Shirt best stripe (color) +シャツベストチェック(色)=Shirt best check (color) +シャツワンピース(水)=Shirt dress (water) +シャツワンピース(赤)=Shirt dress (red) +シャツワンピース(青)=Shirt dress (blue) +シャドーボクシング=Shadowboxing +ジャパリまん桃=KG2 Japariman Pink +ジャパリまん白=KG2 Japariman White +ジャパリまん茶=KG2 Japariman Brown +シャベル=Shovel +シャワー=Shower +シャワー(弱)=Shower (Weak) +シャワー(強)=Shower (Strong) +シャワーH=Shower H +シャワーオナニー=Shower Masturbation +シャワーノズル=Shower Nozzle +シャワーノブ=Shower Knob +シャワールーム=Shower Room +シャワールーム個室=Single Shower Stall +シャワールーム前=Shower Room Front +シャワー室=Shower +シャワー室ドア=Shower Door +シャワー室仕切り1=Shower Divider 1 +シャワー室仕切り2=Shower Divider 2 +シャワー室仕切り3=Shower Divider 3 +シャワー強姦=Shower Rape +シャワー覗き=Shower Peeping +ジャングル=Jungle +じゃんけん1=Rock-paper 1 +じゃんけん2=Rock-paper 2 +じゃんけん3=Rock-paper 3 +じゃんけん4=Rock-paper 4 +じゃんけん5=Rock-paper 5 +ジャンスカ(上)=Janska (Upper) +シャンパン=Champagne +シャンパングラス=Champagne Glass +シュータースカート(緑)=Shooter skirt (green) +シュータースカート(青)=Shooter skirt (blue) +シューティング=Shooting Water Gun +シューティンググラス=Shooting Glasses +ジュエルリング(色)=Jewelring (color) +シュシュ=Scrunchie +シュシュA=Scrunchie A +シュシュB=Scrunchie B +ショーツ=Panties +ショーツ=Panties +ショーツの種類=Underwear Type +ショーツの色01=Underwear 01 Color +ショーツの色02=Underwear 02 Color +ショーツの色03=Underwear 03 Color +ショーツの設定=Panties Settings +ショーツを初期の状態に戻す=Restore Default Underwear Settings +ショーツ柄の色01=Underwear Pattern 01 Color +ショーツ柄の色02=Underwear Pattern 02 Color +ショーツ柄の色03=Underwear Pattern 03 Color +ショート=Short +ショート=Short +ショートカーブ=Short curve +ショートカット=Shortcut +ショートジャージ=Short Jersey Shorts +ショートソックス(色)=Short socks (color) +ショートツイン=Short twin +ショートツインアクセ=Short twin access +ショートツインカール=Short Curled Twintails +ショートツインロール=Short Twin Drills +ショートパレオ=Short Pareo +ショートパレオ(単色)=Short Pareo (Single Color) +ショートパンツ=Short Pants +ショートパンツ(水)=Shorts (water) +ショートパンツ(白)=Shorts (white) +ショートパンツ(青)=Shorts (blue) +ショートヘア=Short Hair +ショートボブ=Short Bob +ショタA=Shota A +ショタB=Shota B +ショタC=Shota C +ショック=Shock +ショップシーン=Shop Scene +ショルダーバッグ=Shoulder Bag +ショルダーレスブラウス=Blouse With Shoulder Lace +シリアス=Serious +シリンダー=Cylinder +シリンダー(キャラ)=Cylinder (Character) +シリンダー(通常)=Cylinder (General) +シルエット=silhouette +シルバーハートネックレス=Silver Heart Necklace +シルバーブレスレット=Silver bracelet +しろめし=Rice Bowl +シワ=Wrinkles +シワの深さ=Wrinkle Intensity +しんきゃく=Stretching +シンプル(色)=Simple (color) +シンプルコア1=Simple Core 1 +シンプルコア2=Simple Core 2 +シンプルベッド=Simple Bed +シンプルリング(色)=Simple ring (color) +シンプル机=Simple desk +シンプル棚=Simple shelf +シンプル椅子=Simple chair +すあま=Soup +スイートストライプ(色)=Sweet stripe (color) +スイートストライプ(色変え可能)=Suite Stripe (Custom Color) +スイカ=Watermelon +スイカヘッド=Watermelon head +スイムパンツ=Swim pants +スイムパンツ(色変え可能)=Swim pants (color change possible) +スイング=Swinging Bat +スウィーツスカート(色)=Sweets skirt (color) +スウィーツスカート(色変え可能)=Sweets Skirt (Custom Color) +スウィーツソックス(色)=Sweets socks (color) +スウィーツソックス(色変え可能)=Sweet Socks (Custom Color) +スウィーツニーソ(色)=Sweets Niso (color) +スウィーツニーソ(色変え可能)=Sweet Thigh Highs (Custom Color) +スウィーツパンプス=Sweets pumps +スウィーツフリルリボン(色)=Sweets frills ribbon (color) +スウィーツフリルリボン(色変え可能)=Sweets Ruffle Ribbon (Custom Color) +スウィーツ女体盛り(色)=Sweets female body (color) +スウィーツ女体盛り(色変え可能)=Sweets (Custom Color) +スウィーティー=Sweety +スウィートフリル(色)=Sweet frill (color) +スウィートフリル(色変え可能)=Sweet Ruffle (Custom Color) +スーツ=Suit +スーツ(灰)=Suit (ash) +スーツ(黒)=Suit (black) +スーツキャミソール(カラー)=Suit Camisole (CC) +スーツキャミソール(水)=Suit Camisole (Wed) +スーツパンツ(柄灰)=Suit pants (ashes) +スーツパンツ(橙)=Suit pants (orange) +スーツパンツ(灰)=Suit pants (ash) +スーツパンツ(黒)=Suit pants (black) +スーツパンツ(黒)=Suit pants (black) +スーツパンツ黒=Suit Pants Black +スカート=Skirt +スカートジャージ=Skirt And Long Jersey Shorts +スカーフ(赤)=Scarf (red) +スカーフ(青)=Scarf (blue) +スカーフ(黄)=Scarf (yellow) +スカイドーム(雪山温泉付属)=Skydome (Attached to Snowy) +スカジャン(色変可)=Sukajan Jacket (CC) +スカルヘッド(色)=Skull head (color) +スキップ=Skip +スキップしない=Do not skip +スキップする=Skip +すき焼き=Sukiyaki +スクールバッグ=School bag +スクールライン=School line +スクール水着=School Swimsuit +スクエア=Square Glasses +スクエアA=Square A +スクエアA(色)=Square A (color) +スクエアB=Square B +スクエアB(色)=Square B (color) +スクエアC=Square C +スクエアC(色)=Square C (color) +スクリーン=Screen +スクリーンモード=Screen mode +スクワット=Squatting +スク水(白)=School water (white) +スク水(紺)=School water (navy) +スク水(色)=School water (color) +スク水(色変え可能)=Swimsuit (Custom Color) +スケベイス=Horny Chair +すけべすぎるミルクボディ=Too Lewd Milk Body +スコップ=Scoop +スター=Star +スター(赤)=Star (red) +スター(青)=Star (blue) +スタート=Start +スターライト(赤)=Starlight (red) +スターライト(青)=Starlight (blue) +スタイル=Style +スタジオ=Studio +スタッズレザーアーム=Studded leather arm +スタンガン=Stun Gun +スタンダードショーツ=Standard Panties +スティンガー=Stinger +すてぃんがー=Suteingaー +ステージ1=Stage 1 +ステージ2=Stage 2 +ステージポール=Stage Pole +ステージマイク=Stage Microphone +ステータス情報=Status Information +ステップマシン=Step Machine +ステルス機(垂直)=Stealth aircraft (vertical) +ステルス機(飛行)=Stealth aircraft (flight) +ステルス機(駐機)=Stealth aircraft (tarmac) +ストッキング(栗)=Stockings (chestnuts) +ストッキング(橙)=Stocking (Orange) +ストッキング(白)=Stockings (white) +ストッキング(紫)=Stockings (purple) +ストッキング(色)=Stocking (color) +ストッキング(色変え可能)=Pantyhose (Custom Color) +ストッキング(赤)=Stocking (red) +ストッキング(黒)=Stocking (black) +ストライプ=Vertical Stripes +ストラップパンプス(色)=Strap pumps (color) +ストラップレス=Strapless +ストラップレスブラ=Strapless Bra +ストレート=Straight +ストレートチップ(白)=Straight tip (white) +ストレートチップ(黒)=Straight tip (black) +ストレートポニー=Straight pony +ストレートミディアム=Straight Medium +ストレッチ=Stretching +ストレッチ1=Stretching 1 +ストレッチ1=Stretching 1 +ストレッチ2=Stretching 2 +ストレッチ2=Stretching 2 +ストレッチ3=Stretching 3 +ストレッチ3=Stretching 3 +ストレッチ4=Stretching 4 +ストレッチ4=Stretching 4 +ストロング=Strong +スナップ移動幅=Grid Snap Amount +スニーカー(緑)=Sneaker (green) +スニーカー(赤)=Sneaker (red) +スニーカー(青)=Sneaker (blue) +スニーカー(黒)=Sneaker (black) +スニーカー襟付(白)=Sneakers with collar (white) +すのこ=Slatted Wood +スパイキー前=Spiky Bangs +スパッツ=Spats +スパッツ(灰)=Spats (ashes) +スパッツ(色)=Spats (color) +スパッツ(色変え可能)=Spats (Custom Color) +スパッツ(黒)=Spats (black) +スパンキング=Spanking +スピーカー=Speaker +スピードアップ=Speed up +スピードダウン=Speed ​​Down +スピリッツ・レイ=Spirit Ray +スフィア=Sphere +スフィア(キャラ)=Sphere (Character) +スフィア(通常)=Sphere (General) +スプーン=Spoon +スプレー(濃)=Spray (Thick) +スプレー(白)=Spray (White) +スプレー(薄)=Spray (thin) +スプレー(透明)=Spray (Transparent) +スプレー(黄)=Spray (Yellow) +スペースキーで戻ります=Spacebar To Return +スペード=Spade +スペード(赤)=Spades (red) +スペード(青)=Spade (blue) +すべての音の音量を調整します=Adjust the volume of all sounds +スポーツ=Sports +スポーツBレッグ(白)=Sports B Leg (White) +スポーツBレッグ(紺)=Sports B Leg (Navy) +スポーツグレー=Sports gray +スポーツショーツ=Sports Panties +スポーツタイプ(カラー)=Sports Type Leotard Top (CC) +スポーツタイプA(カラー)=Sports Type Leotard A (CC) +スポーツタイプA透(カラー)=Sports Type Leotard Transparent A (CC) +スポーツタイプB(カラー)=Sports Type Leotard B (CC) +スポーツタイプB透(カラー)=Sports Type Leotard Transparent B (CC) +スポーツパンツ(灰)=Sports pants (ash) +スポーツパンツ(赤)=Sports pants (red) +スポーツパンツ(青)=Sports pants (blue) +スポーツパンツ(黄)=Sports pants (yellow) +スポーツブラ=Sports Bra +スポーツブラック=Sports black +スポーツブルー=Sports Blue +スポーツローライズ(白)=Sports Low Rise (White) +スポーツローライズ(紺)=Sports Low Rise (Navy) +スポーツ赤=Sports red +スポーツ赤(色)=Sports red (color) +スポーツ青=Sports Blue +スポーツ青(色)=Sports Blue (color) +スポットライト=Spotlight +スポットライト(ALL)=Spotlight (ALL) +スポットライト(キャラのみ)=Spotlight (character only) +スポットライト(マップのみ)=Spotlight (map only) +スポット角度=Spot Angle +スマートショート=Smart short +スマートフォーツー=Smart Car +スマホ=Smartphone +スマホを眺める=Looking At Smartphone +スライダー=Slider +スラックス=Slacks +スラックス(灰)=Slack (ash) +スラックス(褐)=Slacks (brown) +スラッシュ=Slash +スリットタイト(灰)=Slit tight (ash) +スリットタイト(白)=Slit tight (white) +スリットタイト(黒)=Slit tight (black) +スリッパ(サンセットホテル)=Slippers (Sunset Hotel) +スリングショット(色)=Sling shot (color) +スリングショット(色変え可能)=Slingshot (Custom Color) +する=Yes +スルー=Pass Through +スレンダー=Slender +スロ01=Slot 01 +スロ02=Slot 02 +スロ03=Slot 03 +スロ04=Slot 04 +スロ05=Slot 05 +スロ06=Slot 06 +スロ07=Slot 07 +スロ08=Slot 08 +スロ09=Slot 09 +スロ10=Slot 10 +スロ11=Slot 11 +スロ12=Slot 12 +スロ13=Slot 13 +スロ14=Slot 14 +スロ15=Slot 15 +スロ16=Slot 16 +スロ17=Slot 17 +スロ18=Slot 18 +スロ19=Slot 19 +スロ20=Slot 20 +スロット01=Slot 01 +スロット01=Slot 01 +スロット01カラー①=Slot 01 Color ① +スロット01カラー②=Slot 01 Color ② +スロット01カラー③=Slot 01 Color ③ +スロット01カラー④=Slot 01 Color ④ +スロット01の親を選択=Slot 01 Parent Selection +スロット01の調整01=Slot 01 Adjustment 01 +スロット02=Slot 02 +スロット02=Slot 02 +スロット02カラー①=Slot 02 Color ① +スロット02カラー②=Slot 02 Color ② +スロット02カラー③=Slot 02 Color ③ +スロット02カラー④=Slot 02 Color ④ +スロット02の親を選択=Slot 02 Parent Selection +スロット02の調整02=Slot 02 Adjustment 02 +スロット03=Slot 03 +スロット03=Slot 03 +スロット03カラー①=Slot 03 Color ① +スロット03カラー②=Slot 03 Color ② +スロット03カラー③=Slot 03 Color ③ +スロット03カラー④=Slot 03 Color ④ +スロット03の親を選択=Slot 03 Parent Selection +スロット04=Slot 04 +スロット04=Slot 04 +スロット04カラー①=Slot 04 Color ① +スロット04カラー②=Slot 04 Color ② +スロット04カラー③=Slot 04 Color ③ +スロット04カラー④=Slot 04 Color ④ +スロット04の親を選択=Slot 04 Parent Selection +スロット05=Slot 05 +スロット05=Slot 05 +スロット05カラー①=Slot 05 Color ① +スロット05カラー②=Slot 05 Color ② +スロット05カラー③=Slot 05 Color ③ +スロット05カラー④=Slot 05 Color ④ +スロット05の親を選択=Slot 05 Parent Selection +スロット06=Slot 06 +スロット06=Slot 06 +スロット06カラー①=Slot 06 Color ① +スロット06カラー②=Slot 06 Color ② +スロット06カラー③=Slot 06 Color ③ +スロット06カラー④=Slot 06 Color ④ +スロット06の親を選択=Slot 06 Parent Selection +スロット07=Slot 07 +スロット07=Slot 07 +スロット07カラー①=Slot 07 Color ① +スロット07カラー②=Slot 07 Color ② +スロット07カラー③=Slot 07 Color ③ +スロット07カラー④=Slot 07 Color ④ +スロット07の親を選択=Slot 07 Parent Selection +スロット08=Slot 08 +スロット08=Slot 08 +スロット08カラー①=Slot 08 Color ① +スロット08カラー②=Slot 08 Color ② +スロット08カラー③=Slot 08 Color ③ +スロット08カラー④=Slot 08 Color ④ +スロット08の親を選択=Slot 08 Parent Selection +スロット09=Slot 09 +スロット09=Slot 09 +スロット09カラー①=Slot 09 Color ① +スロット09カラー②=Slot 09 Color ② +スロット09カラー③=Slot 09 Color ③ +スロット09カラー④=Slot 09 Color ④ +スロット09の親を選択=Slot 09 Parent Selection +スロット10=Slot 10 +スロット10カラー①=Slot 10 Color ① +スロット10カラー②=Slot 10 Color ② +スロット10カラー③=Slot 10 Color ③ +スロット10カラー④=Slot 10 Color ④ +スロット10の親を選択=Slot 10 Parent Selection +スロット10の調整01=Slot 10 Adjustment 01 +スロット11=Slot 11 +スロット11カラー①=Slot 11 Color ① +スロット11カラー②=Slot 11 Color ② +スロット11カラー③=Slot 11 Color ③ +スロット11カラー④=Slot 11 Color ④ +スロット11の親を選択=Slot 11 Parent Selection +スロット11の調整01=Slot 11 Adjustment 01 +スロット12=Slot 12 +スロット12カラー①=Slot 12 Color ① +スロット12カラー②=Slot 12 Color ② +スロット12カラー③=Slot 12 Color ③ +スロット12カラー④=Slot 12 Color ④ +スロット12の親を選択=Slot 12 Parent Selection +スロット13=Slot 13 +スロット13カラー①=Slot 13 Color ① +スロット13カラー②=Slot 13 Color ② +スロット13カラー③=Slot 13 Color ③ +スロット13カラー④=Slot 13 Color ④ +スロット13の親を選択=Slot 13 Parent Selection +スロット14=Slot 14 +スロット14カラー①=Slot 14 Color ① +スロット14カラー②=Slot 14 Color ② +スロット14カラー③=Slot 14 Color ③ +スロット14カラー④=Slot 14 Color ④ +スロット14の親を選択=Slot 14 Parent Selection +スロット15=Slot 15 +スロット15カラー①=Slot 15 Color ① +スロット15カラー②=Slot 15 Color ② +スロット15カラー③=Slot 15 Color ③ +スロット15カラー④=Slot 15 Color ④ +スロット15の親を選択=Slot 15 Parent Selection +スロット16=Slot 16 +スロット16カラー①=Slot 16 Color ① +スロット16カラー②=Slot 16 Color ② +スロット16カラー③=Slot 16 Color ③ +スロット16カラー④=Slot 16 Color ④ +スロット16の親を選択=Slot 16 Parent Selection +スロット17=Slot 17 +スロット17カラー①=Slot 17 Color ① +スロット17カラー②=Slot 17 Color ② +スロット17カラー③=Slot 17 Color ③ +スロット17カラー④=Slot 17 Color ④ +スロット17の親を選択=Slot 17 Parent Selection +スロット18=Slot 18 +スロット18カラー①=Slot 18 Color ① +スロット18カラー②=Slot 18 Color ② +スロット18カラー③=Slot 18 Color ③ +スロット18カラー④=Slot 19 Color ④ +スロット18の親を選択=Slot 18 Parent Selection +スロット19=Slot 19 +スロット19カラー①=Slot 19 Color ① +スロット19カラー②=Slot 19 Color ② +スロット19カラー③=Slot 19 Color ③ +スロット19の親を選択=Slot 19 Parent Selection +スロット20=Slot 20 +スロット20カラー①=Slot 20 Color ① +スロット20カラー②=Slot 20 Color ② +スロット20カラー③=Slot 20 Color ③ +スロット20カラー④=Slot 20 Color ④ +スロット20の親を選択=Slot 20 Parent Selection +スロット20の調整02=Slot 20 Adjustment 02 +スロットコピー時に左右の親を切り替え=Switching left and right parents during slot copy +スロットのコピー=Copy of slot +スロットをコピー=Copy Slot +セーブ=Save +セーブしました=Game saved. +セーブデータ00を上書き保存しますか?=Would you like to overwrite save data 00? +セーブデータ00を削除しますか?=Do you want to delete save data 00? +セーブデータ00を読込みますか?=Do you want to load save data 00? +セーブデータ01を上書き保存しますか?=Would you like to overwrite save data 01? +セーブデータ01を削除しますか?=Do you want to delete save data 01? +セーブデータ01を読込みますか?=Do you want to load save data 01? +セーブデータ02を上書き保存しますか?=Would you like to overwrite save data 02? +セーブデータ02を削除しますか?=Do you want to delete save data 02? +セーブデータ02を読込みますか?=Do you want to load save data 02? +セーブデータ03を上書き保存しますか?=Would you like to overwrite save data 03? +セーブデータ03を削除しますか?=Do you want to delete save data 03? +セーブデータ03を読込みますか?=Do you want to load save data 03? +セーブデータ04を上書き保存しますか?=Would you like to overwrite save data 04? +セーブデータ04を削除しますか?=Do you want to delete save data 04? +セーブデータ04を読込みますか?=Do you want to load save data 04? +セーブデータ05を上書き保存しますか?=Would you like to overwrite save data 05? +セーブデータ05を削除しますか?=Do you want to delete save data 05? +セーブデータ05を読込みますか?=Do you want to load save data 05? +セーブデータ06を上書き保存しますか?=Would you like to overwrite save data 06? +セーブデータ06を削除しますか?=Do you want to delete save data 06? +セーブデータ06を読込みますか?=Do you want to load save data 06? +セーブデータ07を上書き保存しますか?=Would you like to overwrite save data 07? +セーブデータ07を削除しますか?=Do you want to delete save data 07? +セーブデータ07を読込みますか?=Do you want to load save data 07? +セーブデータ08を上書き保存しますか?=Would you like to overwrite save data 08? +セーブデータ08を削除しますか?=Do you want to delete save data 08? +セーブデータ08を読込みますか?=Do you want to load save data 08? +セーブデータ09を上書き保存しますか?=Would you like to overwrite save data 09? +セーブデータ09を削除しますか?=Do you want to delete save data 09? +セーブデータ09を読込みますか?=Do you want to load save data 09? +セーブデータ10を上書き保存しますか?=Would you like to overwrite save data 10? +セーブデータ10を削除しますか?=Do you want to delete save data 10? +セーブデータ10を読込みますか?=Do you want to load save data 10? +セーブデータ11を上書き保存しますか?=Would you like to overwrite save data 11? +セーブデータ11を削除しますか?=Do you want to delete save data 11? +セーブデータ11を読込みますか?=Do you want to load save data 11? +セーブデータ12を上書き保存しますか?=Would you like to overwrite save data 12? +セーブデータ12を削除しますか?=Do you want to delete save data 12? +セーブデータ12を読込みますか?=Do you want to load save data 12? +セーブデータ13を上書き保存しますか?=Would you like to overwrite save data 13? +セーブデータ13を削除しますか?=Do you want to delete save data 13? +セーブデータ13を読込みますか?=Do you want to load save data 13? +セーブデータ14を上書き保存しますか?=Would you like to overwrite save data 14? +セーブデータ14を削除しますか?=Do you want to delete save data 14? +セーブデータ14を読込みますか?=Do you want to load save data 14? +セーブデータ15を上書き保存しますか?=Would you like to overwrite save data 15? +セーブデータ15を削除しますか?=Do you want to delete save data 15? +セーブデータ15を読込みますか?=Do you want to load save data 15? +セーブデータ16を上書き保存しますか?=Would you like to overwrite save data 16? +セーブデータ16を削除しますか?=Do you want to delete save data 16? +セーブデータ16を読込みますか?=Do you want to load save data 16? +セーブデータ17を上書き保存しますか?=Would you like to overwrite save data 17? +セーブデータ17を削除しますか?=Do you want to delete save data 17? +セーブデータ17を読込みますか?=Do you want to load save data 17? +セーブデータ18を上書き保存しますか?=Would you like to overwrite save data 18? +セーブデータ18を削除しますか?=Do you want to delete save data 18? +セーブデータ18を読込みますか?=Do you want to load save data 18? +セーブデータ19を上書き保存しますか?=Would you like to overwrite save data 19? +セーブデータ19を削除しますか?=Do you want to delete save data 19? +セーブデータ19を読込みますか?=Do you want to load save data 19? +セーブデータ20を上書き保存しますか?=Would you like to overwrite save data 20? +セーブデータ20を削除しますか?=Do you want to delete save data 20? +セーブデータ20を読込みますか?=Do you want to load save data 20? +セーブデータ21を上書き保存しますか?=Would you like to overwrite save data 21? +セーブデータ21を削除しますか?=Do you want to delete save data 21? +セーブデータ21を読込みますか?=Do you want to load save data 21? +セーブデータ22を上書き保存しますか?=Would you like to overwrite save data 22? +セーブデータ22を削除しますか?=Do you want to delete save data 22? +セーブデータ22を読込みますか?=Do you want to load save data 22? +セーブデータ23を上書き保存しますか?=Would you like to overwrite save data 23? +セーブデータ23を削除しますか?=Do you want to delete save data 23? +セーブデータ23を読込みますか?=Do you want to load save data 23? +セーブデータ24を上書き保存しますか?=Would you like to overwrite save data 24? +セーブデータ24を削除しますか?=Do you want to delete save data 24? +セーブデータ24を読込みますか?=Do you want to load save data 24? +セーブデータ25を上書き保存しますか?=Would you like to overwrite save data 25? +セーブデータ25を削除しますか?=Do you want to delete save data 25? +セーブデータ25を読込みますか?=Do you want to load save data 25? +セーブデータ26を上書き保存しますか?=Would you like to overwrite save data 26? +セーブデータ26を削除しますか?=Do you want to delete save data 26? +セーブデータ26を読込みますか?=Do you want to load save data 26? +セーブデータ27を上書き保存しますか?=Would you like to overwrite save data 27? +セーブデータ27を削除しますか?=Do you want to delete save data 27? +セーブデータ27を読込みますか?=Do you want to load save data 27? +セーブデータ28を上書き保存しますか?=Would you like to overwrite save data 28? +セーブデータ28を削除しますか?=Do you want to delete save data 28? +セーブデータ28を読込みますか?=Do you want to load save data 28? +セーブデータ29を上書き保存しますか?=Would you like to overwrite save data 29? +セーブデータ29を削除しますか?=Do you want to delete save data 29? +セーブデータ29を読込みますか?=Do you want to load save data 29? +セーブデータ30を上書き保存しますか?=Would you like to overwrite save data 30? +セーブデータ30を削除しますか?=Do you want to delete save data 30? +セーブデータ30を読込みますか?=Do you want to load save data 30? +セーブデータ31を上書き保存しますか?=Would you like to overwrite save data 31? +セーブデータ31を削除しますか?=Do you want to delete save data 31? +セーブデータ31を読込みますか?=Do you want to load save data 31? +セーブデータ32を上書き保存しますか?=Would you like to overwrite save data 32? +セーブデータ32を削除しますか?=Do you want to delete save data 32? +セーブデータ32を読込みますか?=Do you want to load save data 32? +セーブデータ33を上書き保存しますか?=Would you like to overwrite save data 33? +セーブデータ33を削除しますか?=Do you want to delete save data 33? +セーブデータ33を読込みますか?=Do you want to load save data 33? +セーブデータ34を上書き保存しますか?=Would you like to overwrite save data 34? +セーブデータ34を削除しますか?=Do you want to delete save data 34? +セーブデータ34を読込みますか?=Do you want to load save data 34? +セーブデータ35を上書き保存しますか?=Would you like to overwrite save data 35? +セーブデータ35を削除しますか?=Do you want to delete save data 35? +セーブデータ35を読込みますか?=Do you want to load save data 35? +セーブデータ36を上書き保存しますか?=Would you like to overwrite save data 36? +セーブデータ36を削除しますか?=Do you want to delete save data 36? +セーブデータ36を読込みますか?=Do you want to load save data 36? +セーブデータ37を上書き保存しますか?=Would you like to overwrite save data 37? +セーブデータ37を削除しますか?=Do you want to delete save data 37? +セーブデータ37を読込みますか?=Do you want to load save data 37? +セーブデータ38を上書き保存しますか?=Would you like to overwrite save data 38? +セーブデータ38を削除しますか?=Do you want to delete save data 38? +セーブデータ38を読込みますか?=Do you want to load save data 38? +セーブデータ39を上書き保存しますか?=Would you like to overwrite save data 39? +セーブデータ39を削除しますか?=Do you want to delete save data 39? +セーブデータ39を読込みますか?=Do you want to load save data 39? +セーブデータ40を上書き保存しますか?=Would you like to overwrite save data 40? +セーブデータ40を削除しますか?=Do you want to delete save data 40? +セーブデータ40を読込みますか?=Do you want to load save data 40? +セーブデータ41を上書き保存しますか?=Would you like to overwrite save data 41? +セーブデータ41を削除しますか?=Do you want to delete save data 41? +セーブデータ41を読込みますか?=Do you want to load save data 41? +セーブデータ42を上書き保存しますか?=Would you like to overwrite save data 42? +セーブデータ42を削除しますか?=Do you want to delete save data 42? +セーブデータ42を読込みますか?=Do you want to load save data 42? +セーブデータ43を上書き保存しますか?=Would you like to overwrite save data 43? +セーブデータ43を削除しますか?=Do you want to delete save data 43? +セーブデータ43を読込みますか?=Do you want to load save data 43? +セーブデータ44を上書き保存しますか?=Would you like to overwrite save data 44? +セーブデータ44を削除しますか?=Do you want to delete save data 44? +セーブデータ44を読込みますか?=Do you want to load save data 44? +セーブデータ45を上書き保存しますか?=Would you like to overwrite save data 45? +セーブデータ45を削除しますか?=Do you want to delete save data 45? +セーブデータ45を読込みますか?=Do you want to load save data 45? +セーブデータ46を上書き保存しますか?=Would you like to overwrite save data 46? +セーブデータ46を削除しますか?=Do you want to delete save data 46? +セーブデータ46を読込みますか?=Do you want to load save data 46? +セーブデータ47を上書き保存しますか?=Would you like to overwrite save data 47? +セーブデータ47を削除しますか?=Do you want to delete save data 47? +セーブデータ47を読込みますか?=Do you want to load save data 47? +セーブデータ48を上書き保存しますか?=Would you like to overwrite save data 48? +セーブデータ48を削除しますか?=Do you want to delete save data 48? +セーブデータ48を読込みますか?=Do you want to load save data 48? +セーブデータ49を上書き保存しますか?=Would you like to overwrite save data 49? +セーブデータ49を削除しますか?=Do you want to delete save data 49? +セーブデータ49を読込みますか?=Do you want to load save data 49? +セーブデータ50を上書き保存しますか?=Would you like to overwrite save data 50? +セーブデータ50を削除しますか?=Do you want to delete save data 50? +セーブデータ50を読込みますか?=Do you want to load save data 50? +セーブデータを選択して下さい=Select save data +セーラー(色)=Sailor (color) +セーラー(色変え可能)=Sailor (Custom Color) +セーラースイマー=Sailor swimmer +セーラースカート(色)=Sailor skirt (color) +セーラースカート(色変え可能)=Sailor Skirt (Custom Color) +セーラータイプ=Sailor Type +セーラーワンピース(白)=Sailor one piece (white) +セーラーワンピース(紺)=Sailor one piece (navy blue) +セーラーワンピースA(色)=Sailor one piece A (color) +セーラーワンピースA(色変え可能)=Sailor One-Piece A (Custom Color) +セーラーワンピースB(色)=Sailor one piece B (color) +セーラーワンピースB(色変え可能)=Sailor One-Piece B (Custom Color) +セーラーワンピース白=Sailor One-piece White +セーラーワンピース紺=Sailor One-piece Navy +セーラー服=Sailor Suit +セーラー服(橙)=Sailor suit (orange) +セーラー服(灰)=Sailor suit (ash) +セーラー服(紺)=Sailor uniform (navy blue) +セーラー服A=Sailor suit A +セーラー服B=Sailor suit B +セーラー袖(色)=Sailor sleeve (color) +セーラー袖(色変え可能)=Sailor Sleeve (Custom Color) +セキュリティーキャップ=Security cap +セキュリティーキャップ01=Security cap 01 +セクシー=Sexy +セクシー1=Sexy 1 +セクシー2=Sexy 2 +セクシー3=Sexy 3 +セクシーBスカート(色)=Sexy B skirt (color) +セクシーBブーツ(色)=Sexy B boots (color) +セクシーBリストバンド(色)=Sexy B wristband (color) +セクシーBレギンス(色)=Sexy B Leggings (color) +セクシーエプロン(色)=Sexy apron (color) +セクシーエプロン(色変え可能)=Sexy Apron (Custom Color) +セクシーシューター(緑)=Sexy shooter (green) +セクシーシューター(緑)=Sexy shooter (green) +セクシーシューター(青)=Sexy Shooter (Blue) +セクシーシューター(青)=Sexy Shooter (Blue) +セクシーシューター緑=Sexy Shooter Green +セクシーシューター青=Sexy Shooter Blue +セクシーセキュリティー=Sexy security +セクシーセキュリティーショートブーツ=Sexy Security Short Boots +セクシーセキュリティーロングブーツ=Sexy Security Long Boots +セクシータイトスカート=Sexy Tight Skirt +セクシーダンス=Sexy Dance +セクシーナース=Sexy nurse +セクシーナース(色)=Sexy nurse (color) +セクシーナース(色変え可能)=Sexy Nurse (Custom Color) +セクシーナースキャップ(色)=Sexy nurse cap (color) +セクシーナースジャケット(色)=Sexy nurse jacket (color) +セクシーナースジャケット(色変え可能)=Sexy Nurse Jacket (Custom Color) +セクシーナーススカート(色)=Sexy nurse skirt (color) +セクシーナーススカート(色変え可能)=Sexy Nurse Skirt (Custom Color) +セクシーナースブローチ(色)=Sexy nurse brooch (color) +セクシーナース改=Sexy Nurse Revised +セクシーナース改(色変え可能)=Sexy Nurse Reform (CC) +セクシーなハイニーソ(色)=Sexy honeyso (color) +セクシーなハイニーソ(色変え可能)=Sexy One Piece (Custom Color) +セクシーな下着=Sexy underwear +セクシーな下着(色)=Sexy underwear (color) +セクシーな下着(色変え可能)=Sexy Underware (Custom Color) +セクシーな下着セット=Sexy Underwear Set +セクシーな水着(色)=Sexy swimwear (color) +セクシーな水着(色変え可能)=Sexy Swimsuit (CC) +セクシーパレオ=Sexy Pareo +セクシーボンデージ(色)=Sexy bondage (color) +セクシーマジシャン(色)=Sexy magician (color) +セクシーマジシャン(色変え可能)=Sexy Magician (Custom Color) +セクシーメイドビキニ=Sexy Maid Bikini +セクシーメイドビキニ(色)=Sexy maid bikini (color) +セクシーメイドビキニ(色変え可能)=Sexy Maid Bikini (Custom Color) +セクシーライン=Sexy Line +セクシーライン(色)=Sexy line (color) +セクシーライン(色変え可能)=Sexy Line (CC) +セクシーラインセット=Sexy Line Set +セクシーランジェリー=Sexy Lingerie +セクシーランジェリー(上)=Sexy Lingerie (Top) +セクシーランジェリー(下)=Sexy Lingerie (Bottom) +セダン=Sedan +セダン前扉右=Sedan Front Door Right +セダン前扉左=Sedan Front Door Left +セダン前輪=Sedan Front Wheel +セダン後扉右=Sedan Back Door Right +セダン後扉左=Sedan Back Door Left +セダン本体=Sedan Body +セット=Sets +セット情報のコピー=Copy Clothing Set +セット髪=Hair sets +セット髪の設定=Hair Sets +セピア=Sepia +セミオート=Semi-auto +セミショート=Semi-short +セミロング=Semi-long +セミロング=Semi-long +セリフ=Personality +セリフリスト=Dialogue List +セルフシャドウ=Self-Shadowing +セルフシャドウを有効にする=Enable Self-Shadowing +センター分けシャギー=Center divided Shaggy +センター分けショート=Center separation short +センター分けロング=Center divided long +ソーセージ=Sausage +ソート=Sort +ソードスカル=Sword And Skull +ソードスカル(白)=Sword skull (white) +ソードスカル(黒)=Sword skull (black) +ソープH1=Soap H 1 +ソープH2=Soap H 2 +ソープマット=Thorpe Mat +ソックス(柄灰)=Socks (ashes) +ソックス(柄紺)=Socks (dark blue) +ソックス(柄赤)=Socks (pattern red) +ソックス(白)=Socks (white) +ソックス(黒)=Socks (black) +ソックス・パンスト=Socks and pantyhose +ソックスカラー=Socks color +ソックス縞+カラー=Socks stripes + color +そのまま続ける=Continue +その他=Miscellaneous +そばかす=Freckle +そばかす1=Freckles 1 +そばかす2=Freckles 2 +ソファ1=Sofa 1 +ソファ2=Sofa 2 +ソファーでまったり=Relaxing On Sofa +ソファ騎乗位=Sofa Cowgirl +ソフトクリーム=Ice Cream Cone +ソフトクリームバニラ=Soft Cream Vanilla +そらす=Avert Gaze +そり=Sled +そり跡=Pubic Stubble +ダークウィザード=Dark Wizard +ダークミストエウリノーム=Dark Mist Eurynome +ターゲット=Target +ターゲット描画=Show Target Box +ターゲット描画切替=Show Target Boxes +ターゲット表示=Target Display +タートルワンピ(橙)=Turtle dress (orange) +タートルワンピ(茶)=Turtle dress (tea) +タートルワンピ(黒)=Turtle dress (black) +ダーリン=Darling +ダイア=Diamond +ダイア(色)=Dia (color) +タイタンアラガン=Titan Aragon +タイトスカート=Tight Skirt +タイトスカート(水)=Tight skirt (water) +タイトスカート(灰)=Tight skirt (ash) +タイトスカート(赤)=Tight skirt (red) +タイトスカート(黒)=Tight skirt (black) +タイトパンツ(色)=Tight pants (color) +タイトパンツ(色変え可能)=Tight Pants (Custom Color) +タイトル=Title Screen +タイトルに戻る=Return to title +タイトルへ戻ります。よろしいですか?=Return to Title Screen. Are you sure? +タイトルへ戻りますか?=Return to title? +タイトル画面へ=Title Screen +タイトル画面へ戻りますか?=Do you want to return to the title screen? +タイプ=Type +ダイブ=Diving +タイプ01=Type 01 +タイプ01=Type 01 +タイプ02=Type 02 +タイプ02=Type 02 +タイプ03=Type 03 +タイプ03=Type 03 +タイプ04=Type 04 +タイプ04=Type 04 +タイプ05=Type 05 +タイプ05=Type 05 +タイプ06=Type 06 +タイプ06=Type 06 +タイプ07=Type 07 +タイプ07=Type 07 +タイプ08=Type 08 +タイプ08=Type 08 +タイプ09=Type 09 +タイプ09=Type 09 +タイプ1=Type 1 +ダイブ1=Diving 1 +タイプ10=Type 10 +タイプ10=Type 10 +タイプ11=Type 11 +タイプ11=Type 11 +タイプ12=Type 12 +タイプ12=Type 12 +タイプ13=Type 13 +タイプ13=Type 13 +タイプ14=Type 14 +タイプ14=Type 14 +タイプ15=Type 15 +タイプ15=Type 15 +タイプ16=Type 16 +タイプ16=Type 16 +タイプ17=Type 17 +タイプ17=Type 17 +タイプ18=Type 18 +タイプ18=Type 18 +タイプ19=Type 19 +タイプ19=Type 19 +タイプ2=Type 2 +タイプ2=Type 2 +ダイブ2=Diving 2 +タイプ20=Type 20 +タイプ20=Type 20 +タイプ21=Type 21 +タイプ21=Type 21 +タイプ22=Type 22 +タイプ22=Type 22 +タイプ23=Type 23 +タイプ23=Type 23 +タイプ24=Type 24 +タイプ24=Type 24 +タイプ25=Type 25 +タイプ25=Type 25 +タイプ26=Type 26 +タイプ26=Type 26 +タイプ27=Type 27 +タイプ27=Type 27 +タイプ28=Type 28 +タイプ28=Type 28 +タイプ29=Type 29 +タイプ29=Type 29 +タイプ3=Type 3 +ダイブ3=Diving 3 +タイプ30=Type 30 +タイプ30=Type 30 +タイプ31=Type 31 +タイプ31=Type 31 +タイプ32=Type 32 +タイプ32=Type 32 +タイプ33=Type 33 +タイプ33=Type 33 +タイプ34=Type 34 +タイプ34=Type 34 +タイプ35=Type 35 +タイプ35=Type 35 +タイプ36=Type 36 +タイプ36=Type 36 +タイプ37=Type 37 +タイプ38=Type 38 +タイプ39=Type 39 +タイプ4=Type 4 +ダイブ4=Diving 4 +タイプ40=Type 40 +タイプ41=Type 41 +タイプ42=Type 42 +タイプ43=Type 43 +タイプ44=Type 44 +タイプ45=Type 45 +タイプ46=Type 46 +タイプ47=Type 47 +タイプ48=Type 48 +タイプ49=Type 49 +タイプ5=Type 5 +タイプ50=Type 50 +タイプ51=Type 51 +タイプ52=Type 52 +タイプ53=Type 53 +タイプ54=Type 54 +タイプ55=Type 55 +タイプ56=Type 56 +タイプ57=Type 57 +タイプ58=Type 58 +タイプ59=Type 59 +タイプ6=Type 6 +タイプ60=Type 60 +タイプ61=Type 61 +タイプ62=Type 62 +タイプ63=Type 63 +タイプ64=Type 64 +タイプ65=Type 65 +タイプ66=Type 66 +タイプ67=Type 67 +タイプ68=Type 68 +タイプ69=Type 69 +タイプ7=Type 7 +タイプ70=Type 70 +タイプ71=Type 71 +タイプ72=Type 72 +タイプ73=Type 73 +タイプ74=Type 74 +タイプ75=Type 75 +タイプ76=Type 76 +タイプ77=Type 77 +タイプ8=Type 8 +タイプ9=Type 9 +タイプや種類変更時に前回の親を引き継ぐ=Use Previous Parent When Changing Accessory Type +タイプ別音量設定=Voice Type Volumes +たいやき=Taiyaki +ダイヤモンドの指輪=Diamond ring +タイル床1=Tile Floor 1 +タイル床2=Tile Floor 2 +タイル床3=Tile Floor 3 +ダウンローダー=Downloader +ダウンロード=Download +ダウンロード中...=Downloading ... +タオル(頭乗せ用)=Towel (for riding head) +タオルハンガー=Towel Hanger +タオルハンガー1=Towel hanger 1 +タオルハンガー2=Towel hanger 2 +ダガー=Dagger +ダガー(色)=Dagger (color) +たこ焼き1個=Takoyaki (1) +たこ焼き皿=Takoyaki (Dish) +たこ足配線1=Power Strip 1 +たこ足配線2=Power Strip 2 +たこ足配線3=Power Strip 3 +たすき掛け着物(色)=Crossing kimono (color) +たすき掛け着物(色変え可能)=Tasuki Kimono (Custom Color) +たたんだ眼鏡=Folded glasses +タッセルローファー(紺)=Tassel Loafer (Navy) +タッセルローファー(茶)=Tassel Loafer (brown) +タッセルローファー(黄)=Tassel Loafer (Yellow) +タッセルローファー(黒)=Tassel Loafer (black) +タトゥー=Tattoo +タトゥー=Face Paint +タトゥー(体)の設定=Tattoos +タトゥー(顔)の設定=Facial Tattoos +タトゥーの設定=Tattoos +タバコ=Cigarette +ダブルチェア=Double chair +ダブルモンク(褐)=Double monk (brown) +ダブルモンク(黒)=Double monk (black) +タライ=Washtub +ダルマ=No Limbs +ダルマ(ボテ腹)=No Limbs (Pregnant) +だるまおとし(槌)=KC Daruma 07 +だるまおとし(橙)=KC Daruma 02 +だるまおとし(白)=KC Daruma 05 +だるまおとし(緑)=KC Daruma 03 +だるまおとし(青)=KC Daruma 06 +だるまおとし(頭)=KC Daruma 01 +だるまおとし(黄)=KC Daruma 04 +タンクトップブラ=Tank Top Bra +タングルショルダー=Tangle Shoulderpad +タングルショルダー(色)=Tangle shoulder (color) +タングルショルダー右用=Tangle Shoulder (Right) +タングルショルダー左用=Tangle Shoulder (Left) +ダンサー=Dancer +ダンサーサークレット(色)=Dancer Circlet (color) +ダンサーサンダル(色)=Dancer sandal (color) +ダンサーサンダル(色変え可能)=Dancer Sandals (Custom Color) +ダンサースーツ(色)=Dancer suit (color) +ダンサースーツ(色変え可能)=Dancer Suit (Custom Color) +ダンサースカート(色)=Dancer skirt (color) +ダンサースカート(色変え可能)=Dancer Skirt (Custom Color) +ダンサースリーブ(色)=Dancer sleeve (color) +ダンサースリーブ(色変え可能)=Dancer Sleeves (Custom Color) +ダンサーセット=Dancer Set +ダンサーブローチ(色)=Dancer brooch (color) +ダンサーホーズ(色)=Dancer Whores (color) +ダンサーホーズ(色変え可能)=Dancer (Custom Color) +ダンス=Dancing +ダンス1=Dance 1 +ダンス1=Dance 1 +ダンス2=Dance 2 +ダンス2=Dance 2 +ダンス3=Dance 3 +ダンス3=Dance 3 +ダンス4=Dance 4 +ダンス4=Dance 4 +ダンス5=Dance 5 +ダンス5=Dance 5 +ダンス6=Dance 6 +ダンス6=Dance 6 +ダンス7=Dance 7 +ダンス7=Dance 7 +ダンス8=Dance 8 +ダンスシューズ=Dance Shoes +ダンスショー=Dance Show +ダンス練習=Practicing Dancing +ダンス練習待機=About To Practice Dancing +ダンス追加1=Add Dance 1 +ダンス追加2=Add Dance 2 +ダンス追加3=Add Dance 3 +ダンス追加4=Add Dance 4 +ダンス追加5=Add Dance 5 +ダンベル=Dumbbell +ダンベルM=Dumbbell M +ダンベルS=Dumbbell S +ダンボール=Cardboard +ダンボール1=Cardboard 1 +ダンボール2=Cardboard 2 +ダンボール閉=Cardboard closure +ダンボール開=Cardboard opening +チアガーターリボン(右)=Cheerleader Garter Ribbon (Right) +チアガーターリボン(左)=Cheerleader Garter Ribbon (Left) +チアガール=Cheer Girl +チアスカート=Cheerleader Skirt +チアスカート(赤)=Cheer skirt (red) +チアスカート(青)=Cheer skirt (blue) +チアダンス待機=About To Cheer +チアダンス練習1=Cheerleader Practice 1 +チアダンス練習2=Cheerleader Practice 2 +チアトップス=Cheerleader Top +チアブーツ=Cheerleader Boots +チアポンポン(色)=Thiapon Pong (color) +チアリーディング(赤)=Cheerleading (red) +チアリーディング(青)=Cheerleading (blue) +チアリーディング部=Cheerleading Club +チーク=Cheeks +チークの種類=Cheek Type +チークの色=Cheek Color +チークの設定=Cheeks +チーズ=Cheese +チェーンソー=Chainsaw +チェスト=Chest +チェスト茶=Chest (Tea) +チェスト黒=Chest (Black) +チェックA=Checkered A +チェックB=Checkered B +チェックグレー=Check gray +チェックピンク=Check pink +チェックブルー=Check blue +チキン=Chicken +ちくわ=Chikuwa +チマヨ=Chimayo +チャイナ(桃)=China (Peach) +チャイナ(橙)=China (orange) +チャイナ(緑)=China (green) +チャイナ(青)=China (blue) +チャイナシニヨン(前)=China Sinillon (front) +チャイナシニヨン(後ろ)=China Sionillon (behind) +チャイナシニヨン(飾り無し)=China Signona (undecorated) +チャイナシャツ(橙)=China shirt (orange) +チャイナシャツ(青)=China shirt (blue) +チャイナシャツ(黒)=China shirt (black) +チャイナシューズ(桃)=China shoes (peach) +チャイナシューズ(緑)=China shoes (green) +チャイナシューズ(赤)=China shoes (red) +チャイナシューズ(黒)=China shoes (black) +チャイナスリーブ(桃)=China sleeve (peach) +チャイナスリーブ(緑)=China sleeve (green) +チャイナソックス=China Sox +チャイナドレス(白)=China dress (white) +チャイナドレス(赤)=China dress (red) +チャイナドレス(青)=China dress (blue) +チャイナパンツ(橙)=China pants (orange) +チャイナパンツ(青)=China pants (blue) +チャイナパンツ(黒)=China pants (black) +チャイナポンポン=China Pon Pon +チャイナワンピース(桃)=China One Piece (peach) +チャイナワンピース(緑)=China dress (green) +チャイナ分け=China division +ちゃぶ台1=Chabudai 1 +ちゃぶ台2=Chabudai 2 +チューブストラップ(色)=Tube strap (color) +チューブストラップ(色変え可能)=Tube Strap (Custom Color) +チューブトップ(色)=Tube top (color) +チューブトップ(色変え可能)=Tube Top (Custom Color) +チューブトップシャツ=Tube Top +チューブトップライン=Tube top line +チューブワンピースライン=Tube one piece line +チョコケーキ1P=Chocolate Cake (1P) +チョコケーキ7P=Chocolate Cake (7P) +ちょび=Chobi +ちょびあほ毛=Tiny Ahoge +ちょびあほ毛A=Tiny Ahoge A +ちょびあほ毛B=Tiny Ahoge B +チョロイ=Simple +チラシ(厚い)=Flyer (thick) +チラシ(薄い)=Flyer (thin) +チラシを配る=Distributing Leaflets +ちりとり=Dustpan +ちんぐりアナル舐め=Pildriver Rim Job +チングリピストン=Reverse Pildriver +チンコを引き抜く=Pull out dick +ついてきて=Follow me +ツイン=Twin +ツイン=Twintails +ツインおさげ=Low Twintails +ツインカール=Curled Twintails +ツインシュリンプロール=Twin shrimp roll +ツインテール=Twintails +ツインリング=Twin ring +ツインロール=Twin roll +ツインロングおさげ=Long Twintails +ツイン三つ編み=Twin Braids +ツイン右=R. Twin +ツイン左=L. Twin +ツーサイドアップ=Twin Side-Ups +ツーサイドアップ(前)=Two side up (before) +ツーサイドアップ(後ろ)=Two side up (behind) +ツーサイドアップショート=Twin Side-Up Short +ツーブロック=Two block +ツールボックス=Toolbox +つっかけ=Geta Sandles +つば広帽子=Wide-Brimmed Cap +つまらない=Bored +ツヤ1絞り=Gloss 1 intensity +ツヤ1色=Gloss 1 color +ツヤ2絞り=Gloss 2 intensity +ツヤ2色=Gloss 2 color +ツヤの強さ=Gloss +ツヤの種類=Highlight Type +ツヤの色=Shine color +ツヤの質感=Shine +ツヤ色=Gloss color +ツリー=X-Mas Tree +ツリー2=X-Mas Tree 2 +ツンデレ=Tsundere +ティアラ=Tiara +ティーカップ=Tea Cup +ティースプーン=Tea Spoon +ティーソーサー=Tea Saucer +ティーバックブラック=Tea bag black +ティーバックレッド=Tea bag red +ディープスロート=Deepthroat +ティーポット=Tea Pot +ディーラー=Dealer +ディーラータイト(赤)=Dealer tight (red) +ディーラータイト(黒)=Dealer tight (black) +ディーラー服(赤)=Dealer clothes (red) +ディーラー服(黒)=Dealer clothes (black) +ディップバー=Dip bar +ディルド=Dildo +ディルド(ハニー)=Dildo (Honey) +ディルドー=Dildo +ディルドオナニー=Dildo Masturbation +データ=Data +データがありません=There is no data +データを取得しています=Loading data.. +データ一覧の取得に失敗しました=Acquisition of data list failed +デート=Date +デート(ウキウキ)=Date (Cheerful) +デートコーデ=Date Clothes +デートに誘う=Ask on a date +テーブル=Table +テーブル(雪山温泉)=Table (Snowyama Onsen) +テールリボン=Tail Ribbon +テキスト=Text +テキストウィンドウ=Text Window +テキスト表示=Text display +テキスト表示スピード=Text display speed +テキスト表示スピードサンプ=Text Display Speed ​​Sampler +テキスト表示スピードサンプルです=Text display Speed ​​sample +テキスト表示速度=Text Display Speed +テキスト設定=Text +テクニカルエディット=Technical Edit +でこジャギー=Jagged Forehead +でこだし=Forehead-Showing +でこだしウェーブ=Wavy Forehead-Showing +でこだし横流し(右)=Forehead-Showing Sideswept (R) +でこだし横流し(左)=Forehead-Showing Sideswept (L) +でこ出しロング=Leverage lever +デザインレースパープル=Design Lace Purple +デザインレースピンク=Design race pink +デザインレースベージュ=Design race beige +デザインレースホワイト=Design race white +デジタルカメラ=Digital camera +デスクマット=Desk Mat +デッキシュース(青)=Deck shoes (blue) +デッキチェア=Deck chair +デッキチェア\(白\)=Deck Chairs (White) +デッキチェア\(茶\)=Deck Chairs (Tea) +デッキブラシ=Deck Brush +テッシュ=Box Of Tissues +てつじゅうじのふうじん=Tetsu Juuji no Fuujin +テニスウェア=Tennis Top +テニスシャツ=Tennis Shirt +テニススカート=Tennis Skirt +テニスボール=Tennis Ball +テニスラケット=Tennis Racket +デニム=Denim +デニムジャケット=Denim jacket +デニムジャケット(水)=Denim jacket (water) +デニムジャケット(青)=Denim jacket (blue) +デニムシャツ=Denim shirt +デニムスカート=Denim Skirt +デニムタイトスカート=Tight Denim Skirt +デニムマイクロタイトスカート=Denim microtite skirt +デフォルト=Default +デフォルト=Default +デフォルトパース=Default perspective +デフォルメウィンク=Cartoony Wink +デフォルメつむり=Cartoony Closed +デフォルメニコ=Cartoony Smile +デフォルメ泣き=Cartoony Crying +テラスチェアー=Terrace Chair +テラステーブル=Terrace Table +てらちしゅんころら~ゆアサ=Torrashi Shirayori - Asa +デリンジャー銀=Derringer A +デリンジャー黒=Derringer B +テレビ1=TV 1 +テレビ2=TV 2 +テレビ音量=TV volume +テンショウ=Tensho +テント(オープン)=Tent (Open) +テント(ラップ)=Tent (Rap) +テンプルナイト=Temple Knight +てんぷるないと=Tempuru Naito +デンマ音=Electric Wand +ドア=Doors +ドア1=Door 1 +ドア2=Door 2 +ドア3=Door 3 +トイレ=Toilet +トイレ(夕)=Toilet (evening) +トイレ(夜:消灯)=Toilet (night: lights off) +トイレ(夜:点灯)=Toilet (night: lights up) +トイレ(抵抗)=Toilet (resistance) +トイレ(昼)=Toilet (day) +トイレ(脱力)=Toilet (weakness) +トイレH=Toilet H +トイレオナニー=Toilet Masturbation +トイレットペーパー=Toilet paper +トイレットペーパー1=Toiletpaper 1 +トイレットペーパー2=Toiletpaper 2 +トイレットペーパー3=Toiletpaper 3 +トイレで視点を一人称に設定=1st-Person View In Bathroom +トイレドア1=Toilet Door 1 +トイレドア2=Toilet Door 2 +トイレ仕切り1=Toilet Divider 1 +トイレ仕切り2=Toilet Divider 2 +トイレ仕切り3=Toilet Divider 3 +トイレ仕切り4=Toilet Divider 4 +トイレ嫌がり挿入H=Toilet Forced H +トイレ座り1=Sit on Toilet 1 +トイレ座り2=Sit on Toilet 2 +トイレ強姦=Toilet Rape +トイレ我慢=Waiting for Toilet +トイレ覗き=Toilet Peeping +トゥルー・ブラッド=True Blood +トーイングカー(白)=Towing (white) +トーイングカー(黄)=Towing (yellow) +トースト=Toast +トートバッグ=Tote bag +ドキドキ=Excited (Broad) +ドキドキs=Excited (Moderate) +ドキドキss=Excited (Slight) +ドクロ=Skull +ドクロA&B=Skull A & B +ドクロA&B(色)=Skull A & B +ドクロの髪飾り=Skull Ornament +トゲ=Thorn +トゲ(色)=Thorn (color) +どこかで見たことあるような鼻マスク=Nose masks that I have seen somewhere +ドッグタグ=Dog Tag +トップ=Top +トップ(水着)=Top (swimsuit) +トップス=Tops +トップス=Socks +トップス(水着)=Tops (Swimsuit) +トップス(水着)=Tops (Swimsuit) +トップス(水着用)=Tops (Swimwear) +トップス(水着用)の設定=Tops (Swimwear) Settings +トップス:上=Tops: Top +トップスの種類=Top Type +トップスの色01=Top 01 Color +トップスの色02=Top 02 Color +トップスの色03=Top 03 Color +トップスの色04=Top 04 Color +トップスの設定=Tops Settings +トップスを初期の状態に戻す=Restore Default Top Settings +トップス柄の色01=Top Pattern 01 Color +トップス柄の色02=Top Pattern 02 Color +トップス柄の色03=Top Pattern 03 Color +トップス柄の色04=Top Pattern 04 Color +トップス着脱=Toggle top +トナカイ=Reindeer +トナカイカチューシャ=Reindeer Headband +となります。=instead they affect the entire game. +トパーズの指輪=Topaz Ring +ドヤ=Smug +トライアタック=Tri-Attack +とらいあったっく=Torai Attakku +トライアングル=Triangle +トライアングル頬=Triangle cheek +トライアングル額=Triangle amount +トラクター=Tractor +ドラゴン=Dragon +ドラゴンリング=Dragon ring +ドラッグで姿勢変更=Drag to change position +ドラッグ中のカーソル固定=Fixed cursor during dragging +ドラム缶A=Drum Can A +ドラム缶B=Drum Can B +どら焼き=Dorayaki +ドリル(回転式)=Drill (Rotating Type) +ドリル(直突式)=Drill (Direct-Injection Type) +ドリンク缶=Drink Can +トルコキキョウ=Prairie Gentian Flower +ドルフくん=Dolph-kun +ドルフくんの足=Dolph's feet +ドルフくんの頭=Dolph's head +ドルフくん着ぐるみ=Dolph-kun costumer +ドルフくん石像=Dorufu-kun Statue +トレーラー=Trailer +トレーラーヘッド=Trailer Head +トレッキング(緑)=Trekking (green) +トレッキング(赤)=Trekking (red) +トレッキング(青)=Trekking (blue) +トレッキング(黄)=Trekking (yellow) +トレッドミル=Treadmill +トレパン=Sweatpants +トレンカ(色)=Torenka (color) +ドロップスター(緑)=Dropster (green) +ドロップスター(黄)=Dropster (Yellow) +ドロップ平面(キャラ)=Flattened Droplet (General) +ドロップ平面(通常)=Flattened Droplet (General) +ドロップ立体(キャラ)=Thick Droplet (General) +ドロップ立体(通常)=Thick Droplet (General) +ドンブリ(空)=Dongpo Pork +ナース(白)=Nurse (white) +ナース帽子(桃)=Nurse hat (peach) +ナース帽子(白)=Nurse hat (white) +ナース服(桃)=Nurse clothes (peach) +ナース服(白)=Nurse clothes (white) +ナイト=Knight +ナイトセット=Knight Set +ナイトドレス(白)=Night dress (white) +ナイトドレス(赤)=Night dress (red) +ナイトドレス(黒)=Night dress (black) +ナイトバイザー=Knight Visor +ナイトバイザー(色)=Knight visor (color) +ナイトバング=Knight Bangs +ナイフ=Knife +ナイロンボストン=Nylon Boston Bag +ナイロンボストンA=Nylon Boston Bag A +ナイロンボストンB=Nylon Boston Bag B +なぎさ=Nagisa +なし=None +なし:なし=None:None +ナチュラルA=Natural A +ナチュラルB=Natural B +ナチュラルC=Natural C +ナチュラルD=Natural D +ナチュラルE=Natural E +ナツメのスーツ(灰)=Jujube's suit (ash) +なにも=Nothing +ニーソックス=Kneesocks +ニーソックス(カラー)=Thigh High Socks (CC) +ニーソックス(柄白)=Knee socks (patch white) +ニーソックス(柄赤)=Knee socks (pattern red) +ニーソックス(柄青)=Knee socks (pattern blue) +ニーソックス(柄黄)=Knee socks (handle yellow) +ニーソックス(白)=Knee socks (white) +ニーソックス(色)=Knee socks (color) +ニーソックス(色変え可能)=Knee Socks (Custom Color) +ニーソックス(赤)=Knee socks (red) +ニーソックス(黒)=Knee socks (black) +ニーソックスプレミアム=Knee socks premium +にく=Difficulty +にげあし=Nigeashi +ニンジン=Carrot +ヌカコーラQ=Nuka Cola Q +ヌカコーラQ蓋無し=Nuka Cola Q (Opened) +ヌク=Pull out +ネイチャーネックレス=Nature necklace +ネイティブライン=Native Line +ネオ・ジオング=NeoZeong +ネオ・ジオング(無脚)=NeoZeong. (Nleg) +ネクタイ=Necktie +ネクタイ(色)=Tie (color) +ネクタイショート(色)=Tie short (color) +ネクタイブレザー(男)=Necktie Blazer (Male) +ネクタイブレザー(紺)=Tie blazer (dark blue) +ネクタイリボン(色)=Tie ribbon (color) +ネクタイリボン(赤)=Tie ribbon (red) +ネクタイリボン(青)=Tie ribbon (blue) +ネグリジェ=Négligée +ネジ=Screw +ネッカチーフ(色)=Neckerchief (color) +ネット=Net +ネットワークから=Online +ノイズ=Noise +ノイズの強さを調整します=Adjust the intensity of noise +ノースリーブシャツ=Sleeveless Dress Shirt +ノースリーブワンピース=Sleeveless One-Piece +ノート1=Notebook 1 +ノート1=Note 1 +ノート2=Notebook 2 +ノート2=Note 2 +ノートPC=Note PC +ノートPC=Laptop +ノーハンド先舐め=Licking Penis Tip +のじゃっ子=Old-Fashioned +ノスタルジー=Nostalgia +のど輪=Throat Guard +のむ=Swallowing +のむIN=Start Swallowing +のむ事後=After Swallowing +ノルデック=Nordic +のれん(おでん屋台用)=Goodwill (For Oden Stand) +バーウェイトレス普オレンジ=Honeybee Waitress White Top +バーウェイトレス普ブラック=Honeybee Waitress Black Top +バーウェイトレス短オレンジ=Honeybee Waitress Short White Top +バーウェイトレス短ブラック=Honeybee Waitress Short Black Top +パーカー(桃)=Parker (peach) +パーカー(水)=Parker (Wed) +パーカー(灰)=Parker (ash) +パーカー(緑)=Parker (green) +パーカー(色)=Parker (color) +パーカー(色変え可能)=Parka (Custom Color) +パーカーショ-ト丈(灰)=Parker short height (ash) +パーカーショ-ト丈(赤)=Parka short length (red) +パーカーショ-ト丈(黄)=Parka short height (yellow) +パーカー前開き=Open Parka +バーコード=Barcode +バーコード(腕)=Bar code (arm) +バーコード(首)=Bar code (neck) +バーサーカー=Berserker +バーサーカー(色)=Berserker (color) +バーサーカー(色変え可能)=Berserker (CC) +バーサーカーセット=Berserker Set +バーサーカーの三つ編みA(色)=Berserker's braid A (color) +バーサーカーの三つ編みB(色)=Berserker's braid B (color) +バーサーカーの肩当て右用(色)=Berserker's shoulder for right (color) +バーサーカーの肩当て左用(色)=Berserker's shoulder for the left (color) +バーサーカーの腕当て右用(色)=For Berserker's arm rest right (color) +バーサーカーの腕当て左用(色)=Berserker's arm rest Left (color) +バーサーカーの腰飾り(色)=Berserker's waist ornament (color) +バーサーカーブーツ(色)=Berserker boots (color) +バーサーカーブーツ(色変え可能)=Berserker Boots (CC) +バーサーカー三つ編みA=Berserker's Braid A +バーサーカー三つ編みB=Berserker's Braid B +バーサーカー肩当て右=Berserker Shoulder Right +バーサーカー肩当て左=Berserker Shoulder Left +バーサーカー腕当て右=Berserker Arm Right +バーサーカー腕当て左=Berserker Arm Left +バーサーカー腰飾り=Berserker Waist Cloth +パーソナルフローター=Personal Floater +パーツA=Part A +パーツB=Part B +パーツC=Part C +パーティーハット=Party Hat +パーティクル=Particles +パーティクル(マップ)を有効にする=Particle (Map) +パーテーション=Partition +ハート=Heart +ハート(色)=Heart (color) +ハート1=Heart 1 +ハート1(キャラ)=Heart 1 (Character) +ハート1(通常)=Heart 1 (General) +ハート2=Heart 2 +ハート2(キャラ)=Heart 2 (Character) +ハート2(通常)=Heart 2 (General) +ハートA=Heart A +ハートA(色)=Heart A +ハートB=Heart B +ハートB(色)=Heart B +ハートあほ毛=Heart Ahoge +ハートあほ毛A=Heart Ahoge A +ハートあほ毛B=Heart Ahoge B +ハートインカム=Heart Headset +ハードスイング=Hard Swing +はーどすいんぐ=Haado Suingu +ハートセット=Heart Set +ハートニップレス(色)=Heart nipres (color) +ハートニップレス(色変え可能)=Heart Shaped Pasties (Custom Color) +ハートネックレス=Heart necklace +ハートのバレッタ=Heart Barette +ハートのペンダント=Heart Pendant +ハートの指輪=Heart Ring +ハートの髪飾り=Heart Ornament +ハートブレイク=Heartbreak +ハートブレイク(色)=Heartbreak +ハートペンダント=Heart Pendant +ハードル=Hurdle +ハードルオナニー=Hurdle Masturbation +ハードレザー=Hard leather +ハードレザーアーマー(色)=Hard Leather Armor (color) +ハードレザーアーマー(色変え可能)=Hard Leather Armor (Custom Color) +ハードレザーグローブ=Hard leather gloves +ハードレザースーツ=Hard leather suit +ハードレザーブーツ=Hard Leather Boots +ハードレザーブーツ(色)=Hard leather boots (color) +ハードレザーブーツ(色変え可能)=Hard Leather Boots (Custom Color) +ハードレザーヘルム(色)=Hard leather helm (color) +ハードレザーヘルム額当てあり(色)=Hard leather helm forehead Yes (color) +ハート目=Heart eyes +ハート腕時計=Heart Wristwatch +ハーフアーマー(色)=Half Armor (color) +ハーフアーマー(色変え可能)=Half Armor (Custom Color) +ハーフアップ=Half-Up +ハーフグリーヴ(色)=Half Greave (color) +ハーフグリーヴ(色変え可能)=Shin Armor (Custom Color) +ハーフジャージ=Long Jersey Shorts +ハーフトップドレス=Half-top Dress +ハーフトップブラ=Half-Top Bra +ハーフパンツ=Half pants +ハーフパンツ(水)=Half pants (water) +ハーフパンツ(灰)=Half pants (ash) +ハーフパンツ(紺)=Half pants (navy) +ハーフパンツ(赤)=Half pants (red) +バーベル=C2D05 Weight Barbell +ハーリキンチェック=Harlequin Checkered +パールキャミソール(色)=Pearl Camisole (color) +パールキャミソール(色変え可能)=Pearl Camisole (CC) +パールグローブ(色)=Pearl glove (color) +パールシューズ=Pearl shoes +パールスリーブ(色)=Pearl sleeve (color) +パールスリーブ(色変え可能)=Pearl Sleeve (Custom Color) +パールネックレス(色)=Pearl necklace (color) +パールハイニーソ(色)=Pearl Hi Niso (color) +パールビキニ=Pearl bikini +パールビキニ(色)=Pearl bikini (color) +パールビキニ(色変え可能)=Pearl Bikini (CC) +パールビキニセット=Pearl Bikini Set +パールホーズ(色)=Pearl hose (color) +パールホーズ(色変え可能)=Pearl Hose (Custom Color) +はい=Yes +ハイウエスト(色)=High waist (color) +ハイウエスト(色変え可能)=High Waist Legging (Custom Color) +ハイガード=High Guard +ハイカットスニーカー=High-Cut Sneakers +ハイクオリティメイド=High Quality Maid +パイズリ=Paizuri +パイズリ+咥え=Paizuri & Sucking +パイズリ咥え=Sucking Boobjob +パイズリ舐め=Licking Boobjob +ハイソックス=High Socks +ハイソックス(白)=High Socks (White) +ハイソックス(紺)=High Socks (Navy) +ハイソックス(黒)=High Socks (Black) +ハイビスカス=Hibiscus +ハイビスカス(色)=Hibiscus (color) +バイブ=Vibe +バイブ(ハニー)=Vibe (Honey) +バイブ\(ピンク\)=Vibe (Pink) +バイブ\(指し棒\)=Vibe (Pointing Stick) +バイブ\(触手\)=Vibe (Tentacles) +バイブ1=Vibe 1 +パイプ1(キャラ)=Pipe 1 (Character) +パイプ1(通常)=Pipe 1 (General) +バイブ2=Vibe 2 +パイプ2(キャラ)=Pipe 2 (Character) +パイプ2(通常)=Pipe 2 (General) +バイブ3=Vibe 3 +バイブ4=Vibe 4 +バイブオナニー=Vibe Masturbation +パイプ椅子=Folding Chair +パイプ椅子1=Pipe Chair 1 +パイプ椅子2=Pipe Chair 2 +パイプ椅子3=Pipe Chair 3 +バイブ音=Vibrator +ハイライト=Highlight +ハイライトの下色=Lower Highlight Color +ハイライトの設定=Highlights +ハイライト上の上下位置=Upper Highlight Vertical +ハイライト上の種類=Upper Highlight Type +ハイライト上の色=Upper Highlight Color +ハイライト下の上下位置=Lower Highlight Vertical +ハイライト下の種類=Lower Highlight Type +ハイライト下の色=Lower Highlight Color +ハイレグレオタード=High-Leg Leotard +ハイレッグショーツ=Hi-Leg Panties +バインダー=Binder +パウンドケーキ=Pound Cake +バエル前髪=Bael bangs +バエル後ろ髪=Bael back hair +はく=Spit Out +はく①=Spit① +はく②=Spit② +はくIN=Start Spitting Out +はく事後=After Spitting Out +バケツ=Bucket +バケツ1=Bucket 1 +バケツ2=Bucket 2 +はじめる=Start +パジャマ=Pajamas +パジャマ(ピンク)=Pajamas (pink) +パジャマ(上)=Pajama Top +パジャマ(下)=Pajama Pants +パジャマ(色)=Pajamas (color) +パジャマ(色変え可能)=Pajamas (Custom Color) +パジャマ(青)=Pajamas (blue) +パジャマ柄(桃)=Pajama pattern (peach) +パジャマ柄(青)=Pajamas handle (blue) +バスケットゴール=Basketball Backboard +バスタードソード=Bastard Sword +バスタオル=Bath towel +バスタオル(桃)=Bath towel (peach) +バスタオル(白)=Bath towel (white) +バスト=Breast +はずむ=Bouncing +バス停=Bus Station +バス停(田舎)=Bus Stop (Countryside) +パソコンデスク白=Computer Desk (White) +パソコンデスク茶=Computer Desk (Tea) +パソコンデスク黒=Computer Desk (Black) +パターン=Pattern +パターン01=Pattern 01 +パターン02=Pattern 02 +パターン03=Pattern 03 +パターン04=Pattern 04 +パターン05=Pattern 05 +パターン06=Pattern 06 +パターン07=Pattern 07 +パターン08=Pattern 08 +パターン09=Pattern 09 +はだけ=Exposed +パタパタ=Flapping +パックのお茶=Tea Box +バックラー=Shield +バックラー(色)=Buckler (color) +バックライトの強さ=Backlight intensity +バッジ=Badge +ハッシュ確認...=Hash confirmation ... +ぱっつんエアインテーク=Straight-Cut, Air Intake +ぱっつんサイドショート=Paddock side short +ぱっつんシャギー=Petit Shaggy +ぱっつんショート=Pad Punk Short +ぱっつんストレート=Pants straight +ぱっつんベリショ=Petit BERISHO +ぱっつんボブ=Straight-Cut Bang Bob +ぱっつんロング=Pad Long +バッテン=Batten +ハッピー=Happy +バトル=Battle +バトル・激突=Battle · Clash +バトル・脅威=Battle · Threat +バトル・覚醒=Battle · Begin +バトルアーマー=Battle Armor +バトルカードメニュー=Battle Card Menu +バトルカード作成=Battle Card Creator +バトルスーツ(色)=Battle suit (color) +バトルスーツ(色変え可能)=Battle Suit (Custom Color) +バトルタイツ=Battle Tights +バトルの速度設定=Battle speed setting +バトルビジュアル設定=Battle Visual Setting +バトルブーツ(色)=Battle boots (color) +バトルブーツ(色変え可能)=Battle Boots (Custom Color) +バトルベルト(色)=Battle belt (color) +バトルベルト(色変え可能)=Battle Belt (Custom Color) +バトルモード=Battle Mode +バトルローブ(色)=Battle lobe (color) +バトルローブ(色変え可能)=Battle Robe (Custom Color) +バトル中の確認スキップ=Skip Battles +バナナ=Banana +バナナ1=Banana 1 +バナナ1=Banana 1 +バナナ2=Banana 2 +バナナ2=Banana 2 +バナナジュース=Banana Juice +バナナボート=Banana Boat +バナナ皮剥け=Banana (Peeling) +バニー(色)=Bunny (color) +バニー(赤)=Bunny (red) +バニー(黒)=Bunny (black) +バニーカチューシャ(色)=Bunny headband (color) +バニーカチューシャ(赤)=Bunny headband (red) +バニーカチューシャ(黒)=Bunny headband (black) +バニーカフス=Vanikafusu +ハニーコスチューム(色)=Honey costume (color) +ハニーコスチューム(色変え可能)=Honey Costume (Custom Color) +ハニージャケット(色)=Honey jacket (color) +ハニージャケット(色変え可能)=Honey Jacket (Custom Color) +バニースーツ=Bunny Suit +バニースーツ(色)=Bunny suit (color) +バニースーツ(色変え可能)=Bunny Suit (Custom Color) +バニースーツ(赤)=Bunny suit (red) +バニースーツ(黒)=Bunny suit (black) +ハニースカート(色)=Honey skirt (color) +ハニースカート(色変え可能)=Honey Skirt (Custom Color) +ハニーセレクト=Honey Select +バニーネクタイ(色)=Bunny tie (color) +バニーネクタイ(赤)=Bunny tie (red) +バニーネクタイ(黒)=Bunny tie (black) +ハニーバンド(色)=Honey band (color) +ハニーブーツ(色)=Honey boots (color) +ハニーブーツ(色変え可能)=Honey Boots (Custom Color) +ハネぱっつん=Straight Bangs, Swept Up +ハネミディアム=Medium Bangs, Swept Up +はねロング=Feathered Long +はね毛=Featherlike +パピヨン=Papillon +パピヨン(色)=Papillon (color) +パピヨン(赤)=Papillon (red) +パピヨン(青)=Papillon (blue) +バブルシャワー=Shower Bubbles +ハヤク=Faster +バラ=Rose +パラソル=Parasol +パラソル1=Parasol 1 +パラソル2=Parasol 2 +パラソル2=Parasol 2 +パラソル3=Parasol 3 +バラのイヤリング(全色)=Rose earrings (all colors) +バラのイヤリング(色)=Rose earrings (color) +バラのコサージュ(色)=Rose corsage (color) +バラのコサージュ(色)=Rose corsage (color) +バラのネックレス(色)=Rose necklace (color) +バラのネックレス(色)=Rose necklace (color) +はらぺこ=Hungry +バリア・ピラミッド(緑)=Pyramidal Energy Barrier (Green) +バリア・ピラミッド(赤)=Pyramidal Energy Barrier (Red) +バリア・円(緑)=Spherical Energy Barrier (Green) +バリア・円(赤)=Spherical Energy Barrier (Red) +バリア・四角(緑)=Cubic Energy Barrier (Green) +バリア・四角(赤)=Cubic Energy Barrier (Red) +バリケードA=Barricade A +バリケードB=Barricade B +バリスタ=Ballista +バリスタの槍=Ballista Javelin +ハルバード=Halberd +ハルバード(色)=Halberd (color) +バルバトス=Barbatos +バルバトス(色)=Barbatos (color) +バレー1=Volley 1 +バレー2=Volley 2 +バレー3=Volley 3 +バレー4=Volley 4 +バレエシューズ(色)=Ballet shoes (color) +バレエシューズ(色変え可能)=Ballet Shoes (Custom Color) +バレーボール=Volleyball +パレオ=Pareo Skirt +パレオ(赤)=Pareo (red) +パレオ・改=Pareo Revised +パレオ・改(透)=Pareo Revised (Transparent) +パレットA=Palette A +パレットB=Palette B +ハロウィンヘアー(前)=Halloween hair (front) +ハロウィンヘアー(後ろ)=Halloween hair (behind) +パワーラック=Power Rack +バン=Van +パン1=Pan 1 +パン2=Bread 2 +ハンガー=Hanger +ハンガーラック=Hanger rack +ハンカチ=Handkerchief +パンスト=Pantyhose +パンスト=Pantyhose +パンストA=Pantyhose A +パンストB=Pantyhose B +パンストカラー=Panty color +パンストなど=Pantyhose +パンストなどの設定=Pantyhose Settings +パンストの種類=Pantyhose Type +パンストの色01=Pantyhose 01 Color +パンストの色02=Pantyhose 02 Color +パンストの色03=Pantyhose 03 Color +パンストを初期の状態に戻す=Restore Default Pantyhose Settings +パンスト柄の色01=Pantyhose Pattern 01 Color +パンスト柄の色02=Pantyhose Pattern 02 Color +パンスト柄の色03=Pantyhose Pattern 03 Color +パンスト着脱=Toggle pantyhose +パンダぬいぐるみ=Panda Doll +パンチ=Punch +パンツ着脱=Toggle pants +パンティ(桃)=Panty (peach) +パンティ(白)=Panty (white) +パンティ(縞)=Panties (stripes) +パンティ(黒)=Panty (black) +バンディットクロー(色)=Bandit Claw (color) +バンディットクロー(色変え可能)=Bandit Claw (Custom Color) +バンディットスーツ(色)=Bandit suit (color) +バンディットスーツ(色変え可能)=Bandit Suit (Custom Color) +バンディットソックス(色)=Bandit Socks (color) +バンディットソックス(色変え可能)=Bandit Socks (Custom Color) +バンディットブーツ(色)=Bandit boots (color) +バンディットブーツ(色変え可能)=Bandit Boots (Custom Color) +バンディットベルト(色)=Bandit belt (color) +バンディットベルト(色変え可能)=Bandit Belt (Custom Color) +ハンドドライヤー=Hand dryer +ハンドルネーム=Nickname +ハンドルネーム(16文字以内)=Handle name (within 16 characters) +ハンドルネームを入力して下さい=Please Enter A Nickname. +ハンバーグ=Hamburger +パンプス=Pumps +パンプス(灰)=Pumps (ash) +パンプス(白)=Pumps (white) +パンプス(赤)=Pumps (red) +パンプス(黒)=Pumps (black) +パンプスカバー(橙)=Pumps cover (orange) +パンプスカバー(白)=Pumps cover (white) +パンプスカバー(黒)=Pumps cover (black) +はんぺん=Hanpen +バン前輪=Van Front Wheel +バン後扉右=Van Back Door Right +バン後扉左=Van Back Door Left +ビアチューブワンピ=Via tube dressing +ピアノ椅子=Piano Chair +ピース=Peace +ビーチサンダル=Beach Sandals +ビーチサンダル(白)=Beach sandals (white) +ビーチサンダル(緑)=Beach sandals (green) +ビーチサンダル(色)=Beach sandals (color) +ビーチサンダル(色変え可能)=Beach sandals (color changeable) +ビーチサンダル(青)=Beach sandal (blue) +ビーチサンダル(黄)=Beach sandal (yellow) +ビーチサンダル(黒)=Beach sandals (black) +ビーチチェア=Beach Chair +ビーチパラソル=Beach Parasol +ビーチボール=Beach Ball +ビーチボール1=Beach Ball 1 +ビーチボール2=Beach Ball 2 +ビーチボール3=Beach Ball 3 +ビーチボール4=Beach Ball 4 +ビーチマット=Beach Mat +ヒートホーク=Heat Hawk Ax +ビーム・剣=Energy Beam (Sword) +ビーム・扇=Energy Beam (Folding Fan) +ヒーラーローブセット=Healer Robe Set +ビール=Beer Mug +ビール(グラス)01=Beer (Glass) 01 +ビール1=Beer 1 +ビール2=Beer 2 +ビール瓶=Beer bottle +ヒーローブレード=Hero Blade +ヒーローレイピア=Hero Rapier +ピエロの鼻=Clown Nose +ピエロの鼻(色)=Clown's nose (color) +ピエロ帽魔法少女=Clown Hat Magical Girl +ビキニアーマー=Bikini Armor +ビキニアーマー(色)=Bikini armor (color) +ビキニアーマー(色変え可能)=Bikini Armor (Custom Color) +ビキニアーマーセット=Bikini Armor Set +ビキニアーマーネック(色)=Bikini armor neck (color) +ビキニアーマーパッド(色)=Bikini Armor Pad (color) +ビキニアーマーブーツ(色)=Bikini armor boots (color) +ビキニアーマーブーツ(色変え可能)=Bikini Armor Boots (Custom Color) +ビキニアーマーボトム(色)=Bikini armor bottom (color) +ビキニアーマーボトム(色変え可能)=Bikini Armor Bottom (Custom Color) +ビキニアーマーリスト(色)=Bikini armor list (color) +ビキニラインA=Bikini line A +ビキニラインB=Bikini line B +ビキニ水着=Bikini Swimsuit +ヒゲ=Beard +ヒゲの設定=Beard +ピコハン=Pikohan Hammer +ピザ=Pizza +ビジネスバッグ=Business Bag +ビジュアル=Visual +ビジュアルあり=Visuals? +ビジュアルの個別設定=Individual setting of visual +ビジュアルの再生=Visual Playback +ビジュアル一括設定=All Units Visual Settings +ビジュアル表示=Display Visuals +ビジュアル非表示=Hide Visuals +ピストル=Pistol +ピストン=Piston +ピストン1(早)=Piston 1 (early) +ピストン1(遅)=Piston 1 (late) +ピストン2(早)=Piston 2 (early) +ピストン2(遅)=Piston 2 (late) +ピッカー=Picker +ビッグスター=Big Star +ビッチ=Slutty +ピッチラック=Pitch rack +ピッチラック白=Pitch Rack (White) +ヒットエフェクト1=Hit Effect 1 +ヒットエフェクト2=Hit Effect 2 +ビデオカメラ=Video camera +ヒトデ=Starfish +ひねくれ=Reluctant +ビネット=Vignette +ビネットの強さを調整します=Adjust the strength of the vignette +ビビッド=Vivid +ヒマティオン=Himation +ヒマティオン(色)=Himation (color) +ヒマティオンセット=Himation Set +ひまわり=Sunflower +ヒモショーツ(色)=Pimp shorts (color) +ヒモショーツ(色変え可能)=String (Custom Color) +ヒモブラ(色)=Limpra (color) +ヒモブラ(色変え可能)=String (Custom Color) +ヒョウ=Leopard Print +ひょうたん平面(キャラ)=Flattened Gourd (General) +ひょうたん平面(通常)=Flattened Gourd (General) +ひょうたん立体(キャラ)=Thick Gourd (General) +ひょうたん立体(通常)=Thick Gourd (General) +ピラミッド=Pyramid +ピラミッド(キャラ)=Pyramid (Character) +ピラミッド(通常)=Pyramid (General) +ビラ配り=Distribution of Flyers +ビル1=Building 1 +ビル2=Building 2 +ビル3=Building 3 +ビル4=Building 4 +ヒレ型(キャラ)=Fin (Character) +ヒレ型(通常)=Fin (General) +ヒロインのサンプルテキスト=Girl's Sample Text +ヒロインのフォント=Girl's Font +ピンク=Pink +ピンクチャイナ=Pink China +ピンクレパード=Pink leopard +ピンセット=Tweezers +ファーアーム無柄(色変え可能)=Half-top Fur Arms (CC) +ファーアーム豹柄(色変え可能)=Half-top Leopard Print Fur Arms(CC) +ファーハーフトップドレス無柄=Half-top Fur Dress +ファーハーフトップドレス豹柄=Half-top Leopard Print Fur Dress +ファーレッグ無柄(色変え可能)=Half-top Fur Leg (CC) +ファーレッグ豹柄(色変え可能)=Half-top Leopard Print Fur (CC) +ファイティンググローブ=Fighting Gloves +ファイティングシューズ=Fighting Shoes +ファイル選択=Load File +ファニー=Funny +ファンシー=Fancy +ファンシーショーツ=Fancy Panties +ファンタジー=Fantasy +ファンヒーター=Fan Heater +ぷい=Wow +フィーバーダンス=Fever Dance +フィニッシュ=Finish +フィルター=Filter +ブーツサンダル(白)=Boots sandals (white) +ブーツサンダル(赤)=Boots sandals (red) +ブーツサンダル(黄)=Boots sandals (yellow) +ブーツサンダル(黒)=Boots sandals (black) +フードマント(色)=Food cloak (color) +ブーメランパンツ=Boomerang Panties +ブーメランパンツ(色変え可能)=Boomerang pants (color change possible) +プール=Pool +プールH=Pool H +プールパイズリ=Pool Paizuri +プールバック=Doggystyle In Pool +プールロープ1=Pool Rope 1 +プールロープ2=Pool Rope 2 +プール内立ち=Pool +プール座り1=Sitting Poolside 1 +プール座り2=Sitting Poolside 2 +プール座り3=Sitting Poolside 3 +プール机=Pool desk +プール椅子=Pool chair +フェイス=Face +フェイスペイント01の種類=Facepaint 01 Type +フェイスペイント01配置=Facepaint 01 Position +フェイスペイント02の種類=Facepaint 02 Type +フェイスペイント02配置=Facepaint 02 Position +フェイス設定の保存・削除=Save/Delete Face Settings +フェイス設定の保存と削除=Save/Delete Face Settings +フェイス設定の読み込み=Load Face Settings +フェイス設定の読込み=Load Face Settings +フェイス設定名=Face Settings Name +フェース設定名を入力して下さい=Please Enter Face Settings Name +フェード=Fade +フェザーボレロ(色)=Feather Bolero (color) +フェザーボレロ(色変え可能)=Feather Bolero (Custom Color) +フェミニンボブ=Feminine Bob +フェラ=Fellatio +フェラ1=Blowjob 1 +フェラ2=Blowjob 2 +フェラおっとり=Blowjob (Gentle) +フェラツンデレ=Blowjob (Tsundere) +フェラボーイッシュ=Blowjob (Boyish) +フェラヤンデレ=Blowjob (Yandere) +フェラ元気=Blowjob (Energetic) +フェラ几帳面=Blowjob (Diligent) +フェラ大雑把=Blowjob (Easygoing) +フェラ妖艶=Blowjob (Bewitching) +フェラ明るい=Blowjob (Cheerful) +フェラ活発=Blowjob (Active) +フェラ無口=Blowjob (Withdrawn) +フェラ生真面目=Blowjob (Strict) +フェラ誠実=Blowjob (Sincere) +フェンス後背位=Doggystyle Against Fence +フェンス掴まり駅弁=Ekiben Grabbing Fence +フォークリフト=Forklift +フォースカラー=False Color +フォグ=Fog +フォグを有効にする=Enable Fog +フォックスサングラス(色)=Fox sunglasses (color) +フォルダー=New Folder +ふくらはぎ=Calves +ぶたの置物=Pig Ornament +フックネックレス=Hook necklace +フットカバー=Foot Covers +ふとロング=Thick And Long +ブラ=Bra +ブラ=Bra +ブラー=Blur +ブラインド1=Blinds 1 +ブラインド2=Blinds 2 +ブラインド3=Blinds 3 +ブラインド4=Blinds 4 +ブラインド白=Blind (White) +ブラインド黒=Blind (Black) +フライ返し=Spatula +ブラウザを開く=Open browser +ブラウス=Blouse +ブラウス(桃)=Blouse (peach) +ブラウス(水)=Blouse (Wed) +ブラウス(白)=Blouse (white) +ブラシ=Brush +ブラストエフェクト=Blast Effect +ブラックレース(色)=Black lace (color) +ブラックレース(色変え可能)=Black Lace (Custom Color) +フラッグ小屋=Flag Hut +フラットカラー=Flat Color +フラットベンチ=Flat Bench +ブラの種類=Bra Type +ブラの色01=Bra 01 Color +ブラの色02=Bra 02 Color +ブラの色03=Bra 03 Color +ブラの設定=Bra Settings +プラバケツ=Plastic Bucket +フラフープ=Hula Hoop +プラモデル1=Plastic Model 1 +プラモデル2=Plastic Model 2 +フラワーサンダル=Flower Sandals +フラワーネックレス=Flower necklace +フラワーネックレス(色)=Flower necklace (color) +フラワーリング=Flowering +フラワーリング(色)=Flower ring (color) +ブラを初期の状態に戻す=Restore Default Bra Settings +ブラ柄の色01=Bra Pattern 01 Color +ブラ柄の色02=Bra Pattern 02 Color +ブラ柄の色03=Bra Pattern 03 Color +ブラ着脱=Toggle bra +プリーツスカートA=Pleated Skirt A +プリーツスカートB=Pleated Skirt B +プリーツスカートミニ=Pleated Miniskirt +プリーツスカートロングA=Long Pleated Skirt A +プリーツマスク=Sickness Mask +ブリーフ1枚(色変え可能)=1 brief (can change color) +プリセット=Preset +フリック操作=Swiping Smartphone Screen +ブリッジピストン=Double Decker +ブリム帽子(白)=Brim hat (white) +ブリム帽子(黒)=Brim hat (black) +フリルガーターリング(右)=Frilly Garter Ribbon (Right) +フリルガーターリング(左)=Frilly Garter Ribbon (Left) +フリルスカート(桃)=Frill skirt (peach) +フリルスカート(水)=Frilled skirt (water) +フリルスリーブ(白)=Frilled Sleeves (White Trim) +フリルスリーブ(色変え)=Frilled Sleeves (CC) +フリルスリーブ(黒)=Frilled Sleeves (Black Trim) +フリルタイトスカート=Frilly Tight Skirt +フリルタンキニ(紺)=Frill tankini (navy blue) +フリルタンキニ(赤)=Frilled tankini (red) +フリルニーソックス=Frilly Kneesocks +フリルビキニ(桃)=Frilled bikini (peach) +フリルビキニ(水)=Frilled bikini (water) +フリルワンピ(紺)=Frill dress (navy blue) +フリルワンピ(赤)=Frill dress (red) +フリルワンピース=Frilly One-Piece Dress +フリルワンピース(水)=Frill dress (water) +フリルワンピース(白)=Frill one piece (white) +フリルワンピース(黒)=Frill one piece (black) +プリンター=Printer +フル=Loop +ブルーアクセント=Blue Accents +ブルーム=Bloom +ブルームの強さを調整します=Adjust the strength of Bloom +ブルームを有効にする=Enable Bloom +ブルーム効果にレンズの汚れを加味します=Adding dirt on the lens to Bloom effect +フルオート=Full auto +フルスクリーン=Full screen +ブルマ=Bloomers +ブルマ(水色)=Bloomers (light blue) +ブルマ(紺)=Bulma (Navy) +ブルマ(赤)=Bulma (red) +フレア・ミラージュ=Flare Mirage +フレアスカート(桃)=Flare skirt (peach) +フレアスカート(白)=Flare skirt (white) +フレアスカート(黒)=Flare skirt (black) +フレアスカートA=Flared Skirt A +フレアスカートB=Flared Skirt B +ブレイズスタンプ=Blaze Stamp +フレイム・ロンド=Flame Rondo +プレイヤーキャラに反映=Apply Appearance +プレイヤーを選択して下さい=Please Select a Player Character +フレーム=Frame +フレームレス=Frame Lenses +ブレザー(橙)=Blazer (Orange) +ブレザー(紺)=Blazer (Navy) +ブレザーA=Blazer A +ブレザーA前開き=Blazer A (Opened) +ブレザーB=Blazer B +ブレザーC=Blazer C +ブレザーC(ライン色固定)=Blazer C (Fixed Line Color) +ブレザーC前開き=Blazer C (Opened) +ブレザーC前開き(ライン色固定)=Blazer C (Opened) (Fixed Line Color) +プレジデント用机=President's Desk +プレゼントボックス=Gift Box +プレゼント袋=Gift Bag +プレビュー=Preview +プレミアム=Premium +フレンドリー=Friendly +ブレンド率=Blend ratio +フロアマット桃=Floor Mat (Peach) +フロアマット緑=Floor Mat (Green) +フロアマット黒=Floor Mat (Black) +ブロウ=Blow +ブロウ(色)=Blow (color) +フローリング濃=Flooring (Dark) +フローリング薄=Flooring (Thin) +ブロック=Block +ブロック壁1=Block Wall 1 +ブロック壁2=Block Wall 2 +ブロック壁3=Block Wall 3 +ブロッサムサンダル=Blossom Sandals +プロペラントタンク=NeoZeong (Tank) +プロペラ羽=Propeller feather +プロローグ=Prologue +プロローグ強姦=Prologue rape +フロントレース=Front Lace +ふわカール=Fluffy Curled +ふわツインウェーブ=Fluffy Wavy Twintails +ふわポニー=Fluffy Ponytail +ふわポニーロング=Fluffy Long Ponytail +ふんどし=Loincloth +ふんどし(色)=Loincloth (color) +ふんどし(色変え可能)=Loincloth (Custom Color) +ふんどし白=Fukushi white +ふんどし黒=Fukushi black +ふんばる=Entrench +ヘアカラー=Hair color +ヘアスタイル=Hairstyle +ヘアバンド=Hairband +ヘアピン=Hairpin +ヘアピン(色)=Hairpin (color) +ヘアピン右=R. Hairpin +ヘアピン左=L. Hairpin +ペイント=Body Paint +ペイント01サイズ補正=Paint 01 Size +ペイント01の種類=Paint 01 Type +ペイント01の色=Paint 01 Color +ペイント01の配置=Paint 01 Location +ペイント01上下位置=Paint 01 Vertical +ペイント01上下補正=Paint 01 Vertical +ペイント01位置プリセット=Paint 01 Position Presets +ペイント01回転=Paint 01 Rotation +ペイント01大きさ=Paint 01 Size +ペイント01左右位置=Paint 01 Horizontal +ペイント01左右補正=Paint 01 Horizontal +ペイント02サイズ補正=Paint 02 Size +ペイント02の種類=Paint 02 Type +ペイント02の色=Paint 02 Color +ペイント02の配置=Paint 02 Location +ペイント02上下位置=Paint 02 Vertical +ペイント02上下補正=Paint 02 Vertical +ペイント02位置プリセット=Paint 02 Position Presets +ペイント02回転=Paint 02 Rotation +ペイント02大きさ=Paint 02 Size +ペイント02左右位置=Paint 02 Horizontal +ペイント02左右補正=Paint 02 Horizontal +ページ01=Page 01 +ページ02=Page 02 +ページ03=Page 03 +ページ04=Page 04 +ページ05=Page 05 +ベース=Base +ベール付き帽子(色)=Hat with veil (color) +ベスト(褐)=Best (brown) +ベスト(黒)=Best (black) +ベッド=Beds +ヘッドB=Head B +ペットボトルのお茶=Plastic Tea Bottle +ペットボトルの水=Plastic Water Bottle +ペットボトル焼酎=Pet Bottle Shochu +ペットボトル焼酎蓋無し=Pet Bottle Shochu (Opened) +ヘッドホン=Headphones +ヘッドホン(白)=Headphone (white) +ヘッドホン(赤)=Headphone (red) +ヘッドホン(黒)=Headphone (black) +ベッド横=Next to bed +ベッド正面=Bed front +への字=Characters to +ベビードール=Babydoll +ベビードール(C)=Babydoll (CC) +ベビードール(C)透過=Babydoll Transparent (CC) +ベビードールA=Babydoll A +ベビードールA(色)=Babydoll A (color) +ベビードールA(色変え可能)=Baby Doll A (Custom Color) +ベビードールB=Babydoll B +ベビードールB(色)=Babydoll B (color) +ベビードールB(色変え可能)=Baby Doll B (Custom Color) +ベリアル=Belial +ベリアル(色)=Belial (color) +ベリーショート=Berry short +ベリーダンサー(赤)=Belly dancer (red) +ベリーダンサー(青)=Belly dancer (blue) +ベリーダンスアンクレット(緑)=Belly dance anklet (green) +ベリーダンスアンクレット(赤)=Belly dance anklet (red) +ベリーダンスサンダル(水)=Belly Dance Sandals (Wed) +ベリーダンスサンダル(赤)=Belly Dance Sandal (Red) +ベリーダンスネックレス(緑)=Belly dance necklace (green) +ベリーダンスネックレス(赤)=Belly dance necklace (red) +ベリーダンスブレスレット(緑)=Belly dance bracelet (green) +ベリーダンスブレスレット(赤)=Belly dance bracelet (red) +ベリーダンス用(水)=For belly dancing (water) +ベリーダンス用(紫)=Belly dancing (purple) +ベリーダンス用(赤)=Belly dance (red) +ベリーダンス衣装(水)=Belly dance costume (water) +ベリーダンス衣装(赤)=Belly dance costume (red) +ベリーロング=Very Long +ベリーロングストレート=Very Long Straight +ベリーロングツインテール(前)=Berry Long twin tail (front) +ベリーロングツインテール(太い)=Berry Long twin tail (thick) +ベリーロングツインテール(後ろ)=Berry Long twin tail (behind) +ベルト=Belt +ベルトパンプス(桃)=Belt pumps (peach) +ベルトパンプス(水)=Belt pumps (water) +ベルトパンプス(黄)=Belt pumps (yellow) +ベルトパンプス(黒)=Belt pumps (black) +ベルトブーツ=Belt Boots +ヘルメット=Baseball Helmet +ヘルメット赤=Helmet (Red) +ヘルメット黒=Helmet (Black) +ベレー帽=Beret +ペン=Pen +ベンチ=Bench +ベンチ1=Bench 1 +ベンチ2=Bench 2 +ベンチ3=Bench 3 +ベンチで寝る1=Sleeping On Bench 1 +ベンチで寝る2=Sleeping On Bench 2 +ベンチフェラ=Bench Blowjob +ペンライト=Penlight +ボアスリッパ(色変可)=Slippers (CC) +ボイス=Voice +ボイス音量=Voice volume +ホイッスル=Whistle +ホイッスル(単体)=Whistle +ホイップカール=Whip Curl +ポイントクロス(色)=Point Cross (color) +ポイントクロス(色変え可能)=Point Cross (Custom Color) +ポイントの上限=Show Endpoint +ポイントライト=Point Light +ポイントライト(ALL)=Point light (ALL) +ポイントライト(キャラのみ)=Point light (character only) +ポイントライト(マップのみ)=Point light (map only) +ポイント移動=Move Point +ボウズ=Bows +ボーイッシュ=Tomboy +ポーズ=Pose +ポーズ1=Pose 1 +ポーズ10=Pose 10 +ポーズ11=Pose 11 +ポーズ12=Pose 12 +ポーズ13=Pose 13 +ポーズ14=Pose 14 +ポーズ15=Pose 15 +ポーズ16=Pose 16 +ポーズ17=Pose 17 +ポーズ18=Pose 18 +ポーズ19=Pose 19 +ポーズ2=Pose 2 +ポーズ20=Pose 20 +ポーズ21=Pose 21 +ポーズ22=Pose 22 +ポーズ23=Pose 23 +ポーズ24=Pose 24 +ポーズ25=Pose 25 +ポーズ26=Pose 26 +ポーズ27=Pose 27 +ポーズ28=Pose 28 +ポーズ29=Pose 29 +ポーズ3=Pose 3 +ポーズ4=Pose 4 +ポーズ5=Pose 5 +ポーズ6=Pose 6 +ポーズ7=Pose 7 +ポーズ8=Pose 8 +ポーズ9=Pose 9 +ポーズリスト=Pose List +ボーダー=Horizontal Stripes +ボーダーパンツ(色変え可能)=Border pants (color change possible) +ポーチ(色)=Pouch (color) +ボート=Boat +ホーリーランス=Holy Lance +ホーリーランス(色)=Holy Lance (color) +ポール=Pole +ボール1=Ball 1 +ポール1=Pole 1 +ボール2=Ball 2 +ポール2=Pole 2 +ボール3=Ball 3 +ボール4=Ball 4 +ボールギャグ=Ball gag +ボールギャグ=Ball Gag +ポールダンス=Pole Dance +ボールビーズ=Ball Bead Bracelet +ボール入れ=Ball Container +ボーンサンダル(白)=Bone sandals (white) +ボーンサンダル(茶)=Bone sandals (brown) +ボーンサンダル(黄)=Bone sandals (yellow) +ボーンサンダル(黒)=Bone sandal (black) +ぼかしエフェクト=Blur effect +ぼかし四角ハイライト=Gradient Square Highlight +ぼかし帯ハイライト=Gradient Band Highlight +ぼかし線ハイライト=Gradient Line Highlight +ボクサーショーツ(色)=Boxer Shorts +ボクサーショーツ(色変え可能)=Boxer (Custom Color) +ボクシング=Boxing +ボクシングリング=Boxing Ring +ホクロ=Mole +ほくろ=Mole +ホクロの上下位置=Mole Vertical Position +ホクロの大きさ=Mole Size +ホクロの左右位置=Mole Horizontal Position +ホクロの種類=Mole Type +ホクロの色=Mole Color +ホクロの設定=Moles +ホクロ位置プリセット=Mole Position Presets +ホクロ配置=Mole Position +ポスター=Posters +ポスターリュックサック=Backpack With Posters +ポスターを貼る=Putting Up Poster +ほそロング=Fine And Long +ボタンスリットタイト(水)=Button slit tight (water) +ボタンスリットタイト(灰)=Button slit tight (ash) +ボタンスリットタイト(黒)=Button slit tight (black) +ボタンタンクトップ(水)=Button tank top (water) +ボタンタンクトップ(緑)=Button Tank Top (Green) +ボタンタンクトップ(赤)=Button Tank Top (Red) +ぽちゃ=Chubby +ポッキリスウェット(蓋つき)=Plastic Waterbottle (With Lid) +ポッキリスウェット(蓋なし)=Plastic Waterbottle (No Lid) +ボックススカートA=Box Skirt A +ボックススカートB=Box Skirt B +ほっそり=Slender +ポッチャリ=Chubby +ポット=Pot +ホットパンツ=Hotpants +ホットパンツ(水)=Hot pants (water) +ホットパンツ(青)=Hot pants (blue) +ホットパンツ(黒)=Hot pants (black) +ホットパンツセット=Hot Pants Set +ボディー=Body +ボディーカラー=Body color +ボディーペイント01の種類=Body Paint 01 Selection +ボディーペイント01の配置=Body Paint 01 Position +ボディーペイント02の種類=Body Paint 02 Selection +ボディーペイント02の配置=Body Paint 02 Position +ボディー設定の保存・削除=Save/Delete Body Settings +ボディー設定の保存と削除=Save/Delete Body Settings +ボディー設定の読み込み=Load Body Settings +ボディー設定の読込み=Load Body Settings +ホテルスカート(緑)=Hotel skirt (green) +ホテルスカート(青)=Hotel skirt (blue) +ホテルタイトスカート(赤)=Hotel tight skirt (red) +ホテルタイトスカート(黒)=Hotel tight skirt (black) +ホテルのキー=Hotel key +ホテル服(緑)=Hotel clothing (green) +ホテル服(赤)=Hotel clothing (red) +ホテル服(青)=Hotel clothing (blue) +ホテル服(黒)=Hotel clothing (black) +ボテ腹=Pregnant +ボトム=Bottom +ボトム(水着)=Bottom (swimsuit) +ボトムス=Bottoms +ボトムス=Bottom +ボトムス(水着)=Bottoms (Swimsuit) +ボトムス(水着)=Bottoms (Swimsuit) +ボトムス(水着用)=Bottoms (Swimwear) +ボトムス(水着用)の設定=Bottoms (Swimwear) Settings +ボトムスの種類=Bottom Type +ボトムスの色01=Bottom 01 Color +ボトムスの色02=Bottom 02 Color +ボトムスの色03=Bottom 03 Color +ボトムスの設定=Bottoms Settings +ボトムスを初期の状態に戻す=Restore Default Bottom Settings +ボトムス柄の色01=Bottom Pattern 01 Color +ボトムス柄の色02=Bottom Pattern 02 Color +ボトムス柄の色03=Bottom Pattern 03 Color +ボトムス着脱=Toggle bottoms +ポニー=Pony +ポニー=Ponytail +ポニーテール=Ponytail +ボブ=Bob +ボブヘア=Bobbed Hair +ボリュームポニーテール=Thick Ponytail +ホルターネック(橙)=Halter neck (orange) +ホルターネック(緑)=Halter neck (green) +ポルノ映画館=Pornographic Cinema +ボロTシャツ=Boro T-shirt +ボロボロの剣=Rusty Sword +ボロ机=Rolling machine +ボロ椅子=Boro chair +ボロ長靴=Boro boots +ボロ靴下=Boro socks +ホワイト=White +ホワイトボード=Whiteboard +ホワイトボード1=Whiteboard 1 +ホワイトボード2=Whiteboard 2 +ホワイトボード3=Whiteboard 3 +ポンチョコート=Poncho Coat +ボンデージA=Bondage A +ボンデージA(色)=Bondage A (color) +ボンデージA(色変え可能)=Bondage A (Custom Color) +ボンデージB=Bondage B +ボンデージB(色)=Bondage B (color) +ボンデージB(色変え可能)=Bondage B (Custom Color) +ボンデージガーター(色)=Bondage garter (color) +ボンデージガーター(色変え可能)=Bondage Garter (Custom Color) +ボンデージスリーブ(色)=Bondage sleeve (color) +ボンデージスリーブ(色変え可能)=Bondage Sleeve (Custom Color) +ボンデージブーツ(色)=Bondage boots (color) +ボンデージブーツ(色変え可能)=Bondage Boots (Custom Color) +ポンポン=Pom-Pom +ポンポン右用=Right Pom-Pom +ポンポン左用=Left Pom-Pom +マイク=Microphone +マイクロビキニ(色)=Micro bikini (color) +マイクロビキニ(色変え可能)=Micro Bikini (Custom Color) +マイクロビキニ(赤)=Micro bikini (red) +マイクロビキニ(青)=Micro bikini (blue) +マイクロビキニラインA=Micro bikini line A +マイクロビキニラインB=Micro bikini line B +マイクロホルター(色)=Micro Holter (color) +マイクロホルター(色変え可能)=Micro Halter (Custom Color) +マイクロモノキニ=Micro Monokini +マイペース=Own Pace +マウスによるカメラ操作感度を設定します=Set Mouse camera sensitivity +マウス上下反転=Invert horizontal mouse movement direction +マウス型右(キャラ)=Right Mouse Button (General) +マウス型右(通常)=Right Mouse Button (General) +マウス型左(キャラ)=Left Mouse Button (General) +マウス型左(通常)=Left Mouse Button (General) +マウス左右反転=Invert vertical mouse movement direction +マウス感度=Mouse sensitivity +マガジン=Magazine +マガジン(色)=Magazine (color) +マグロの握り=Tuna Nigiri +マジカルステッキ=Magical Stick +マジシャン(赤)=Magician (Red) +マジシャン(黒)=Magician (black) +マジシャンジャケットA(色)=Magician jacket A (color) +マジシャンジャケットA(色変え可能)=Magician Jacket A (Custom Color) +マジシャンジャケットB(色)=Magician jacket B (color) +マジシャンジャケットB(色変え可能)=Magician Jacket B (Custom Color) +マジシャンステッキ(色)=Magician's stick (color) +マジシャンハイニーソA(色)=Magician Hi Niso A (color) +マジシャンハイニーソA(色変え可能)=Magican Socks A (Custom Color) +マジシャンハイニーソB(色)=Magician Hi Niso B (color) +マジシャンハイニーソB(色変え可能)=Magican Socks B (Custom Color) +マジシャンハットA(色)=Magician Hat A (color) +マジシャンハットB(色)=Magician Hat B (color) +マジシャンパンプス(色)=Magician pumps (color) +マジシャンパンプス(色変え可能)=Magician Pumps (Custom Color) +マジシャンリボン(色)=Magician ribbon (color) +マジシャン赤=Magician Red +マジシャン黒=Magician Black +マジックサークレット(色)=Magic circle (color) +マスター音量=Master Volume +マズルフラッシュ=Muzzle Flashes +またお願い=Do it again +まつげ=Eyelashes +マッサージオイル=Massage Oil +マッサージ器=Vibrating Wand +マッサージ器\(ハンマー\)=Massager (Hammer) +マッサージ器\(白\)=Massager (White) +マッサージ器\(黒\)=Massager (Black) +マッサージ器1=Massager 1 +マッサージ器2=Massager 2 +マッサージ器3=Massager 3 +マット1=Mat 1 +マット1=Mat 1 +マット2=Mat 2 +マット2=Mat 2 +マット3=Mat 3 +マット3=Mat 3 +マット4=Mat 4 +マット5=Mat 5 +マップ=Map +マップコントローラー=Map Controller +マップの表示=Show Map +マップの遮蔽表示=Enable Map Masking +マップライト=Map Lights +マップリスト=Map List +マップ依存=Map Dependent +マップ夕方=Map In Evening +マップ移動中=During Map Movement +マップ移動設定=Map Movement Settings +マップ表示切替=Clear Map +マップ読込=Load Map +マップ遮蔽処理=Do Map Shading +マップ選択=Map Selection +マナ・ストリーマー=Mana Streamer +マナ・マスターマスター=Mana Master Master +マニキュア=Manicure +マニュアル=Manual +マニュアル=Manual +マネキン=Mannequin +まぶた形状1=Eyelid shape 1 +まぶた形状①=Eyelid Shape 1 +まぶた形状2=Eyelid shape 12 +まぶた形状②=Eyelid Shape 2 +マフラー=Muffler +マフラー(紫)=Muffler (purple) +マフラー(赤)=Muffler (red) +マフラー(黄)=Muffler (Yellow) +まゆげ=Eyebrows +マリオン=Marion +まりおん=Marion +マリオンのスカート(色)=Marion's skirt (color) +マリオンのスカート(色変え可能)=Marion Skirt (Custom Color) +マリオンのニーソックス(色)=Marion's Knee Socks (color) +マリオンのニーソックス(色変え可能)=Marion Knee Socks (Custom Color) +マリオンの帽子(色)=Marion's hat (color) +マリオンの魔導書=Marion 's magic book +マリオンの魔導書(色)=Marion's magic book (color) +マリオンの魔導服(色)=Marion 's magical clothes (color) +マリオンの魔導服(色変え可能)=Marion Magical Outfit +マル=Maru +マルグレット前髪=Margrette bangs +マルチPスカート(緑)=Multi P skirt (green) +マルチPスカート(赤)=Multi P skirt (red) +マルチPスカート(黄)=Multi P skirt (yellow) +マルチPスカート(黒)=Multi P skirt (black) +マルチマシン1=Multi-Machine 1 +マルチマシン2=Multi-Machine 2 +まろ=Mahoromoto +マンガ肉=Meat on Bone +マンガ肉(齧り)=Meat on Bone (Eat) +まんぐり挿入=Piledriver +マングリ正常位=Piledriver Missionary +まんぐり股間指挿入=Piledriver Insertion +まんぐり股間舐め=Piledriver Cunnilingus +ミーハー=Trendy +ミステリアス=Mysterious +ミディアム=Medium +ミディアムウェーブ=Medium wave +ミディアムシャギー=Medium Shaggy +ミディアムダウン=Medium Down +ミディアムマッシュ=Medium mash +ミドルソックス(カラー)=Mid Length socks (CC) +ミニジャケット=Mini Jacket +ミニジャケット・袖(白)=Mini Jacket With Sleeves (White Trim) +ミニジャケット・袖(色変え)=Mini Jacket With Sleeves (CC) +ミニジャケット・袖(黒)=Mini Jacket With Sleeves (Black Trim) +ミニスカート巫女服=Miko Mini Skirt +ミニタイトスカート=Tight Miniskirt +ミニタイトスカート(色)=Miniteitosukato (color) +ミニタイトスカートストライプ(色)=Minitaito skirt stripe (color) +ミニプリーツ=Mini Pleats +ミニプリーツセーター付き=Mini Pleated Sweater included +ミニ剣客=Mini Swordsmen +ミニ翼右=Mini Wing Right +ミニ翼右用(色)=Mini wing for right (color) +ミニ翼左=Mini Wing Left +ミニ翼左用(色)=Mini wing for left (color) +みぶやよい=Mibu Yayoi +ミラージュ・エフェクト=Mirage Effect +ミリタリーブーツ(砂)=Military boots (sand) +ミリタリーブーツ(黒)=Military boots (black) +ミリンラガービール=Mirin Lager Beer +ムーン=Moon +ムキムキ=Muscular +むせる=Choke +むせる事後=After Choking +ムチ打ち=Whip +むっつり=Gloomy +ムフフ=Mufufu +メイジサークレット(色)=Mage circlet (color) +メイドカチューシャ=Maid headband +メイドカフス右=Maid cuff links right +メイドカフス左=Maid cuffs left +メイドスカート=Maid Skirt +メイドヘアバンド=Maid Hairband +メイド服=Maid clothes +メイド服(カラー)=Maid (CC) +メイド服(黒)=Maid clothes (black) +メイド服・改(カラー)=Maid Alt (CC) +メイド服の袖=Maid Sleeves +メイン=Main +メインカラー=Main Color +メインテーマ=Main Theme +メインの色=Main color +メインメニュー=Main Menu +メインメニューに戻りますか?=Return to Main Menu? +メインメニューへ=Main Menu +メカ=Mecha +メカアンテナ=Mecha Antenna +メカアンテナ1=Mecha Antenna 1 +メカアンテナ2=Mecha Antenna 2 +メカアンプ=Mecha Amplifier +メカウィング=Mechanical wing +メカウイングⅡ=Mecha Wing Ⅱ +メカウィングリング=Mecha Winged Ring +メカグローブ=Mecha Gloves +メカゴーグル=Mechagoguru +メカサークル=Mechanical circle +メカシールド=Mechanical shield +メカシールドⅡ=Mecha Shield Ⅱ +メカシザー=Mechaniser +メカショルダー=Mecha Shoulder +メカスーツ=Mecha Suit +メカソックス=Mecha Socks +メカタイ=Mecha Tie +メカチューブ=Mechanical tube +メカデルタ=Mechanical delta +メカドリル=Mechanical drill +メガネっ娘がいい!=Glasses +メガネ着脱=Toggle glasses +メカパーツ=Mechanical Parts +メカバイザー=Mechanical visor +メカバイザーⅡ=Mecha Visor Ⅱ +メカハンド=Mecha Hands +メカハンド握り右用=Mecha Right Fist +メカハンド握り左用=Mecha Left Fist +メカハンド開き右用=Mecha Right Open Hand +メカハンド開き左用=Mecha Left Open Hand +メカビームポール=Mechanical beam poles +メカブースター=Mechanical booster +メカブースターⅡ=Mecha Booster Ⅱ +メカブーツ=Mecha Boots +メカフット=Mecha Foot +メカフット(右)=Mecha Foot (Right) +メカフット(左)=Mecha Foot (Left) +メカヘアー=Mecha Hair +メカボール=Mechanical ball +メカポール=Mechanpor +メカボックス=Mechanical box +メカポッド=Mechanical Pod +メカモールド1=Mechanical mold 1 +メカモールド2=Mechanical mold 2 +メカループ=Mecha Loop +メカレシーバー=Mecha Receiver +メカ指揮官風=Mechanical Commander-like Style +メカ装甲1=Mechanical armor 1 +メカ装甲2=Mechanical Armor 2 +メカ装甲3=Mechanical Armor 3 +メカ装甲4=Mechanical Armor 4 +メカ装甲5=Mecha Armor 5 +メカ装甲6=Mecha Armor 6 +メカ装甲6×3=Mecha Armor 6x3 +メタルバングル=Metal Bangle +メタルフレーム=Metal frame +メタルフレーム(色)=Metal frame (color) +メッセージウィンドウの色と透過率=Message Window Transparency +メッセージ速度=Message Speed +メロンパン1=Melon Bread 1 +メロンパン2=Melon Bread 2 +メンダコ=Squid +めんだこ=Flapjack Octopus +メンダコ(色)=Mendaco (color) +メンダコヘッド=Squid Misc 2 +メンダコヘッド(2色)=Mendaco Head (2CC) +モザイク=Mosaic +モジモジ=Timid +もどる=Back +モノキニライン=Monokini line +モノキニワンピ(色)=Monokini dress (color) +ものぐさ=Lazy +モノクロ=Monochrome +もの悲しい=Melancholy +モヒカン=Mohawk +モヒカン(色)=Mohawk (color) +モブ=Mob +モフモフアームA(色変え可能)=Mohumov Arm A (CC) +モフモフアームB(色変え可能)=Mohumov Arm B (CC) +モフモフレッグA(色変え可能)=Mohumov Leg A (CC) +モフモフレッグB(色変え可能)=Mohumov Leg B (CC) +モブ男A=Mob Man A +モブ男B=Mob Man B +モブ男C=Mob Man C +もやもや=Hazy +モンキーレンチ=Monkey wrench +モンペ=Monpe +やかん=Kettle +ヤシの木(彎曲)=Palm Tree (Curved) +ヤシの木(直立)=Palm Tree (Upright) +ヤシの木1=Palm tree 1 +ヤシの木2=Palm tree 2 +やせ=Skinny +ヤンデレ=Yandere +ユックリ=Slower +ゆっくり挿入する=Insert slowly +ゆったりロングパンツ=Comfortable Long Pants +ユニコーン=Unicorn +ゆらゆら水面_□=Water Surface (Square) +ゆらゆら水面_●大=Water Surface (Huge) +ゆらゆら水面_〇=Water Surface (Circle) +ゆるふわセミショート=Yu Flow Semi Short +ゆるふわボブ=Loose Fluffy Bob +ゆるふわボブ前=Loose Fluffy Bobbed Bangs +ゆるふわレイヤー=Loose Layer +ゆるふわロング=Loose Loose +ゆるやかカーブ=Gentle curve +ラーメン屋台=Ramen Food Stand +らいせん=Raisen +ライティングを変更=Change lighting +ライト=Light +ライト・シールド=Light Shield +ライト・画面効果=Effects +ライトエッジ=Light Edge +らいとえっじ=Raito Ejju +ライトカラー=Light Color +ライトコントローラー=Light Controller +ライトセーバー(DV)=C2D22 Saber DV +ライトセーバー(QG)=C2D22 Saber QG +ライトニングアタック=Light Shuriken Attack +ライトの向きを初期化=Reset Light Direction +ライトの向き調整=Light Direction +ライトの影響度=Light Influence +ライトロング=Light Long +ライト横=Horizontal Light +ライト縦=Vertical Light +ライブ=Live Concert +ライブステージ=Live Concert Stage +ライフセーバー(赤)=Life saver (red) +ライフセーバー(青)=Life saver (blue) +ライフル=Rifle +ライフル1=Rifle 1 +ライフル2=Rifle 2 +ライフル3=Rifle 3 +ライン=Lines +ラインタンガ=Line Tanga +ラインの太さ=Line Thickness +ラインの幅=Line Width +ラインの描画=Draw Lines +ラインの色=Line Color +ラインペイント=Line paint +ラウンド=Round Glasses +ラウンドパンプス=Round Pumps +ラジオ=Radio +ラッシュ=Rush +ラナンキュラス=Buttercup +ラフ服=Casual Clothes +ラムネ瓶=Lemon Soda Bottle +ランキング=Ranking +ランキング(総合)=Ranking (total) +ランキング(週間)=Ranking (Week) +ランキングに参加=Get Ranked +ランジェリー(白)=Lingerie (white) +ランジェリー(黒)=Lingerie (black) +ランジェリーライン=Lingerie line +ランソックス(紺)=Lansocks (Navy Blue) +ランソックス(赤)=Lansocks (Red) +ランソックス(黒)=Lansocks (Black) +ランダム=Random +ランダムキャラの検索方法=Random Character Source +ランタン=Lanthanum​ +ランドセル(赤)=Loli Backpack (Red) +ランドセル(黒)=Loli Backpack (Black) +ランナー(橙白x黒)=Athletic Bikini (Orange, White & Black) +ランナー(白黄x黒)=Athletic Bikini (White, Yellow & Black) +ランナー(赤黄x紺)=Athletic Bikini (Red, Yellow & Navy Blue) +ランナーライン=Runner Tanline +ランニングウェア=Running Top +ランニングウェア(色)=Running wear (color) +ランニングシューズ=Running Shoes +ランニングシューズ(桃)=Running shoes (peach) +ランニングシューズ(白)=Running shoes (white) +ランニングシューズ(緑)=Running shoes (green) +ランニングシューズ(黄)=Running shoes (yellow) +ランニングショーツ=Running Shorts +ランニングパンツ(色)=Running pants (color) +リアクション=Reaction +リコーダー=Recorder +リストバンド(赤)=Wristband (red) +リストバンド(青)=Wristband (blue) +リストバンド右用=Right Wristband +リストバンド左用=Left Wristband +リストレングス(色)=List length (color) +リストレングス(色変え可能)=Short Gloves (Custom Color) +リセット=Reset +リセット=Reset +リゾートサンダル(茶)=Resort sandals (brown) +リゾートサンダル(赤)=Resort sandals (red) +リゾートサンダル(青)=Resort sandals (blue) +リゾートサンダル(黒)=Resort sandals (black) +リップ=Lips +リップクリームを塗る=Using Lip Balm +リップクリームを塗る待機=About To Use Lip Balm +リップシンク=Lip-Sync +リップの種類=Lip Type +リップの色=Lip Color +リップの設定=Lips +リップラインの種類=Lip Line Type +リップラインの色=Lip Line Color +リナロベール=Lina Robert +リバースカラー=Reverse Color +リバースモノクロ=Reverse Monochrome +リビング=Living +リビング(夕)=Living (evening) +リビング(夜:消灯)=Living (night: lights off) +リビング(夜:点灯)=Living (night: lit) +リビング(昼)=Living (day) +リビング(脱力=Living (weakness +リビング(豹変)=Living (revolving) +リボン=Ribbon +リボン&ベル=Ribbon & Bell +リボン(色)=Ribbon (color) +リボン(色)=Ribbon (color) +リボンショーツ=Ribbon Panties +リボンストラップサンダル=Ribbon-Strap Sandals +リボンチョーカー=Ribbon Choker +リボンなしポニーテール=Ponytail Without Ribbon +リボンなしロングサイド(右)=Long Side Tail Without Ribbon (R) +リボンなしロングサイド(左)=Long Side Tail Without Ribbon (L) +リボンなし結わえロング=Tied Long Without Ribbon +リボンパンプス=Ribbon Pumps +リボンパンプス(色)=Ribbon pumps (color) +リボンパンプス(色変え可能)=Ribbon Pumps (CC) +リボンブラ=Ribbon Bra +リボンペンダント=Ribbon Pendant +リボンポニーショート=Ribbon Pony Short +リボンポニーロング=Ribbon Pony Long +リボンレースーショーツ=Lace Ribbon Panties +リボンレースブラ=Ribbon Lace Bra +リボンロング=Ribbon Long +リボン帯(色)=Ribbon band (color) +リボン帯柄あり(色)=Ribbon strip pattern Yes (color) +リボン帯長(色)=Ribbon strip length (color) +リボン帯長柄あり(色)=Ribbon strip with long pattern (color) +リュック(桃)=Luc (peach) +リュック(緑)=Backpack (green) +リュック(色替)=Backpack (Color Change) +リュック(黒)=Backpack (black) +リュックサック=Backpack +リング=Ring +リング(キャラ)=Ring (Character) +リング(細)=Thin Ring +リング(通常)=Ring (General) +リングジュエル=Jeweled Ring +リングショーツ(色)=Ring shorts (color) +リングショーツ(色変え可能)=Ring (Custom Color) +リングネックレス=Ring necklace +リング式ギャグ=Ring Type Gag +ルーズソックス=Loose Socks +ルーズソックス(白)=Loose socks (white) +ルーズソックス(赤)=Loose socks (red) +ルーズソックス(黒)=Loose socks (black) +ルーズネクタイ(赤)=Loose necktie (red) +ルーズネクタイ(青)=Loose tie (blue) +ルーズネクタイ短=Loose Necktie (Short) +ルーズネクタイ長=Loose Necktie (Long) +ルーズブラウス半袖(色)=Loose blouse Short sleeve (color) +ルーズブラウス半袖(色変え可能)=Loose Blouse Short Sleeve (Custom Color) +ルーズブラウス半袖ブラ見せ(色)=Loose blouse Short sleeve bra show (color) +ルーズブラウス長袖(色)=Loose blouse long sleeve (color) +ルーズブラウス長袖(色変え可能)=Loose Blouse Long Sleeve (Custom Color) +ルーズブラウス長袖ブラ見せ(色)=Loose blouse Long sleeve bra show (color) +ルートシステム=Route System +ループ=Loop +ループIN=Loop Start +ループパターン=Loop Pattern +ルームカラー変更=Room color change +ルーンシールド=Rune Shield +ルーンシールド(色)=Rune shield (color) +ルーンソード=Runesword +ルーンソード(色)=Rune Sword (color) +レイピア=Rapier +レイピア(色)=Rapier (color) +レイヤードパーカー=Layered parka +レイヤードパーカー(灰)=Layered parka (ash) +レイヤードパーカー(白)=Layered hoodies (white) +レイヤードパーカー(紺)=Layered parka (navy) +レイヤードパーカー(緑)=Layered parka (green) +レイヤードパーカー(黒)=Layered hoodies (black) +レース=Lace +レース(ムフフ)=Lace (Mufufu) +レースアップサンダル(色)=Lace-up sandals (color) +レースガーターリング(赤)右=Race garter ring (red) right +レースガーターリング(赤)左=Race garter ring (red) Left +レースガーターリング(黒)右=Race garter ring (black) Right +レースガーターリング(黒)左=Race garter ring (black) Left +レーススルー(色)=Race Through (color) +レーススルー(色変え可能)=Lace See-Through (Custom Color) +レースチョーカー(赤)=Lace Choker (Red) +レースチョーカー(青)=Lace choker (blue) +レースチョーカー(黒)=Lace choker (black) +レーストップショーツ=Lace Topped Panties +レーストップブラ=Lace Top Bra +レースビスチェ=Lace Bustier +レースブラック=Lace Black +レースベージュ=Lace beige +レースホワイト=Lace White +レースリボン(色)=Lace ribbon (color) +レースリボン(色変え可能)=Lace Ribbon (Custom Color) +レースレッド=Lace Red +レオタード=Leotard +レオタードA=Leotard A +レオタードA=Leotard A +レオタードB=Leotard B +レオタードB=Leotard B +レオタードリボン(色)=Leotard ribbon (color) +レオタード半袖(色)=Leotard short sleeve (color) +レオタード半袖(色変え可能)=Leotard Short Sleeves (Custom Color) +レオタード長袖(色)=Leotard long-sleeved (color) +レオタード長袖(色変え可能)=Leotard Long Sleeves (Custom Color) +レギンス=Leggings +レザーアーマー=Leather Armor +レザーアーマーグローブ(色)=Leather Armor Glove (color) +レザーアーマーグローブ(色変え可能)=Leather Armor (Custom Color) +レザーアーマースカート(色)=Leather Armor Skirt (color) +レザーアーマースカート(色変え可能)=Leather Armor Skirt (Custom Color) +レザーアーマーセット=Leather Armor Set +レザーアーマーフリル付き右用(色)=Leather Armor with frill for right (color) +レザーアーマーフリル付き左用(色)=Leather Armor with frill attachment for left (color) +レザーアーマーロンググローブ(色)=Leather Armor Long Gloves (color) +レザーアーマー右用=Leather armor for right +レザーアーマー左用=Leather Armor for Left +レザーアーマー用ハイニーソ=Honeyso for leather armor +レザーグローブ(色)=Leather glove (color) +レザーグローブ(色変え可能)=Leather Glove (Custom Color) +レザースニーカー(色)=Leather sneaker (color) +レザーバッグ=Leather Bag +レザーバングル(白)=Leather bangle (white) +レザーバングル(茶)=Leather Bangle (Brown) +レザーブーツ(色)=Leather boots (color) +レザーブーツ(色)=Leather boots (color) +レザーブーツ(色変え可能)=Leather Boots (Custom Color) +レザーブーツ(色変え可能)=Leather Boots (Custom Color) +レジ1=Register 1 +レジ2=Cashier 2 +レズ=Lesbian +レズ・クンニオナニー=Lesbian Cunnilingus +レズ・股間弄り=Lesbian Fingering +レズAクンニ=Lesbian Cunnilingus A +レズA愛撫=Lesbian Caress A +レズBクンニ=Lesbian Cunnilingus B +レズB愛撫=Lesbian Caress B +レスリングリング=Wrestling Ring +レッグウォーマー=Leg Warmers +レッドアクセント=Red Accents +レッドキャノン=Red Cannon +レッドチャイナミックス=Red China Mix +レトロ=Retro +レトロウェイトレス=Retro Waitress +レトロウェイトレス(色)=Retro waitress (color) +レトロウェイトレス(色変え可能)=Retro Waitress (Custom Color) +レトロウェイトレススカーフ(色)=Retro waitress scarf (color) +レトロウェイトレスタイト(色)=Retro waitress tight (color) +レトロウェイトレスタイト(色変え可能)=Retro Waitress Tight (Custom Color) +レトロなテレビ=Retro TV +レトロなバス=Retro Bus +レトロな冷蔵庫=Retro Refrigerator +レトロな扇風機=Retro Electric Fan +レフトロング=Left Long +レフ板=Lev Plate +レモン=Lemon +レンガ=Brick +レンガ床1=Brick Floor 1 +レンガ床2=Brick Floor 2 +レンズの汚れ=Dirty lens +レンズフレアA=Lens Flare A +レンズフレアA=Lens Flare A +レンズフレアB=Lens Flare B +レンズフレアB=Lens Flare B +レンズフレアC=Lens Flare C +レンズフレアD=Lens Flare D +レンズフレアE=Lens Flare E +レンズフレアF=Lens Flare F +レンズフレアG=Lens Flare G +ロイヤルクラウン=Royal Crown +ロイヤルリボン=Royal Ribbon +ロウソク=Candle +ロウソク2=Candle 2 +ローイングマシン=Rowing Machine +ローション=Lotion Bottle +ロース(焼)=Sirloin +ロース(生)=Sirloin (Raw) +ロースとトング=Sirloin and Tongs +ローター=Rotor +ロード=Load +ロードしました=Scene loaded. +ロードしますか?=Load This Game? +ロードする箇所=Load +ロードデータを選択して下さい=Please Pick Data To Load +ローファー=Loafers +ローファー(右)=Loafer (right) +ローファー(左)=Loafer (left) +ローファー(紺)=Loafer (dark blue) +ローファー(茶)=Loafer (tea) +ローファー(黄)=Loafer (yellow) +ローファー(黒)=Loafer (black) +ローポニー(右)=Ropony (right) +ローラー=Roller +ローライズショーツ=Lowrise Panties +ロール=Roll +ロゴ=Logo +ロッカー=Locker +ロッカー1=Locker 1 +ロッカー2=Locker 2 +ロッカー3=Locker 3 +ロッカー4=Locker 4 +ロッカー5=Locker 5 +ロッカー6=Locker 6 +ロッカールーム=Locker Room +ロッカールーム個室=Single Locker Area +ロックグラス=Ice Glass +ロックグラス2=Ice Glass 2 +ロビー=Lobby +ロビー机=Lobby desk +ロング=Long +ロング=Long +ロングサイド=Longside +ロングサイドテール(右)=Long Side Tail (R) +ロングサイドテール(左)=Long Side Tail (L) +ロングスカート=Janska (Bottom) +ロングストレート=Long straight +ロングスパッツ(カラー)=Long Spats (CC) +ロングソード=Longsword +ロングソードの鞘=Longsword Sheath +ロングツインテール=Long twin tail +ロングドレス=Long Dress +ロングドレス(上)=Long Dress (Top) +ロングドレス(下)=Long Dress (Bottom) +ロングネクタイ=Long Necktie +ロングパンツ=Long Pants +ロングヘア=Long Hair +ロングボウ=Longbow +ロングボウ(色)=Long bow (color) +ロングポニー=Long pony +ロングポニー(頭巾)=Long pony (hood width) +ロングレングス(色)=Long length (color) +ロングレングス(色変え可能)=Long Gloves (Custom Color) +ロングワイシャツ=Long Dress Shirt +ワークスペース=Workspace +ワードローブ=Wardrobe +ワイシャツ=Dress Shirt +ワイシャツ(男)=Dress Shirt (Male) +ワイシャツパーカー=Parka And Dress Shirt +ワイシャツベスト=Vest And Dress Shirt +ワイシャツベスト(男)=Vest And Dress Shirt (Male) +ワイシャツ襟開け=Dress Shirt (Opened Collar) +ワイバーンブーツ(色)=Wyvern boots (color) +ワイバーンブーツ(色変え可能)=Wyvern Boots (Custom Color) +ワイルドキック=Wild Kick +わいるどきっく=Wairudo Kikku +ワイングラス=Wine Glass +ワイングラス・入(2色)=Wineglass · Liquid +ワイングラス・空=Wineglass · Empty +ワイングラス・空(色)=Wineglass · Empty +ワイングラス1=Wine glass 1 +ワイングラス2=Wine glass 2 +ワインボトル=Wine bottle +ワンカップ太関=One Cup Sake +ワンダーバルーン(白)=Wonder balloon (white) +ワンダーバルーン(赤)=Wonder balloon (red) +ワンダーバルーン(青)=Wonder balloon (blue) +ワンダーバルーン(黄)=Wonder balloon (yellow) +ワンピース=One-Piece +ワンピース(無地)=One-Piece Dress (Plain) +ワンピース(白)=One Piece (White) +ワンピース(花柄)=One-Piece Dress (Flower Pattern) +ワンピース(黒)=One Piece (Black) +ワンピース水着(色)=One piece swimming suit (color) +ワンピース水着(色変え可能)=One-Piece (Custom Color) +ワンポイント=Starpoint Earring +ん大=Big N +ん小=Small N +一人好き=Likes Being Alone +一人称=1st-Person +一回のみ再生=Play Once +一括=Set All +一括変更=Change All +一捆线(粉)=A Bundle of Wire (Pink) +一捆线(黑)=A Bundle of Wire (Black) +一文字の傷=One letter wound +一本角(色)=Single corner (color) +一気に挿入する=Insert quickly +一目惚れ=Lovestruck +一礼=Bow +一粒ペンダント=Starpoint Pendant +一緒に帰ろう=Go home together +一角=Unicorn Horn +一輪のバラ=Rose of one wheel +七氏]ベッド=Mr. Seven Bed +七氏]布団A=Mr. Seven Futon A +七氏]布団B=Mr. Seven Futon B +七氏]枕=Mr. Seven Pillow +七輪=Earthen Charcoal Brazier +七部丈パンツ(水)=Seven length pants (water) +七部丈パンツ(青)=Seven length pants (blue) +七部丈パンツ(黒)=Seven length pants (black) +三つ巴(白)=Tomoe Triplet (White) +三つ巴(黒)=Tomoe Triplet (Black) +三つ編み=Braided +三つ編みお団子=Braided Bun +三つ編みサイド=Knitting side +三つ編みツイン=Braid twin +三つ編みフード=Braid hood +三つ編みロング(前)=Braid long (front) +三つ編みロング(後ろ)=Braid long (behind) +三つ編み横おさげ(右)=Horizontal Braid (Right) +三つ編み横おさげ(左)=Horizontal Braid (Left) +三つ葉の指輪=Ring of three leaves +三人称=3rd-Person +三捆绳子=Rope Hand Tie +三日月=Crescent Moon +三日月1(キャラ)=Crescent Moon 1 (Character) +三日月1(通常)=Crescent Moon 1 (General) +三日月2(キャラ)=Crescent Moon 2 (Character) +三日月2(通常)=Crescent Moon 2 (General) +三日月3(キャラ)=Crescent Moon 3 (Character) +三日月3(通常)=Crescent Moon 3 (General) +三结绳子-3分1圆=Rope Mid Curl +三结绳子-4分1圆=Rope Curl +三结绳子-半圆=Rope Extra Curl +三结绳子-垂直=Rope Wth Knots +三角=Triangle +三角(キャラ)=Triangle (Character) +三角(通常)=Triangle (General) +三角テーブル=Triangular Table +三角ブラ=Triangle Bra +三角巾=Bandanna +三角木馬=Spanish Donkey +三角木馬(ハニー)=Triangular Wooden Horse (Honey) +三角木馬1=Triangular Horse 1 +三角木馬2=Triangular Horse 2 +三角木馬3=Triangular Horse 3 +三角木马枷锁=PAME Woodenpony1 +三角横台形(キャラ)=Horizontal Triangle (General) +三角横台形(通常)=Horizontal Triangle (General) +三連石ブレスレット(金)=Triple Stone Bracelet (Fri) +三連石ブレスレット(銀)=Triple stone bracelet (silver) +上=Upward +上まぶたの形状1=Upper Eyelid Shape 1 +上まぶたの形状2=Upper Eyelid Shape 2 +上まぶたの形状3=Upper Eyelid Shape 3 +上下=Height +上下左右移動=XY movement +上下移動=Vertical Move +上半身=Upper body +上履き=Uwabaki +上履き(右)=Shoes (right) +上履き(左)=Shoes (left) +上履き(赤)=Shoes (red) +上履き(青)=Shoes (blue) +上書きしますか?=Do you want to Overwrite? +上書きセーブ=Overwrite +上書き保存=Save +上腕=Arm +上腕の奥=Upper Arm Thickness +上腕の幅=Upper Arm Width +上部上下=Face Height +上部前後=Upper face Depth +上部幅=Upper Thin/Fat +上部形状=Upper Ear Shape +下=Downward +下まぶたの形状1=Lower Eyelid Shape 1 +下まぶたの形状2=Lower Eyelid Shape 2 +下まぶたの形状3=Lower Eyelid Shape 3 +下半身=Lower body +下履き=Outdoor Shoes +下着=Underwear +下着(トップス)=Underwear (Tops) +下着(ボトムス)=Underwear (Bottoms) +下着(ワンピース)=Underwear (One Piece) +下着カラー=Underwear color +下着が非表示状態です=Underwear is invisible +下着上(着)=Underwear (wearing) +下着縞+カラー=Underwear stripes + color +下腕=Lower Arms +下部上下=Thin/Fat +下部前後=Lower face Depth +下部幅=Lower Thin/Fat +下部形状=Lower Ear Shape +下部横幅=Lower face Width +不安=Anxious +不屈の精神=Brave +不幸少女=Pessimist +不慣れ=Inexp. +不明=Unknown +不機嫌=Angry +不死马=Undead Horse +不満=Dissatisfied +不良少女=Delinquent +世間話=Small talk +东都洛阳=East Of Luoyang +両手コキ=Two-Hand Handjob +両手フェラ=Two-Hand Blowjob +両手剣=Two-Handed Sword +両手剣1=Two-Handed Sword 1 +両手剣2=Two-Handed Sword 2 +両手剣3=Two-Handed Sword 3 +両目=Both Eyes +両目の下=Below both eyes +両目の設定を統一する=Make Eyes match +両目を統一する=Make eyes match +両目閉じ=Closed +並び替え条件を選んで下さい=Sort Options +中=Medium +中ドラッグ動作=Center drag action +中に出すよ=I'm cumming inside +中ループ=Medium Loop +中出し=Creampie +中出し(ベース待機)=Cum Inside (Base Wait) +中出し(大ビク)=Cream Pies (big) +中出し(小ビク1)=Cream Pies (Small Bikes 1) +中出し(小ビク2)=Cum Inside (Small Bikes 2) +中出しする=Vaginal cum shot +中出しループ=Come Inside Loop +中出し事後=After Coming Inside +中出し開始=Come Inside Start +中分けぱっつん=Medium Straight-Cut Bangs +中分けミディアム=Medium, Middle Parted +中分ヘア(右)=Even Split (R) +中分ヘア(左)=Even Split (L) +中庭=Courtyard +中式短剑=Chinese Dagger +中式纸伞=Chinese Paper Umbrella +中式长剑=Chinese Sword +中腰1=Kneeling 1 +中腰2=Kneeling 2 +中腰3=Squatting 1 +中腰4=Kneeling 3 +中腰5=Bridging 1 +中腰6=Hands & Knees 1 +中腰7=Hands & Knees 2 +中腰バック=Kneeling Behind +中華そば=Chinese Noodles +中華刀=Chinese Sword +中華照明1=Chinese lighting 1 +中華結び飾り=Chinese knotted decoration +中華風PCデスク=Chinese style PC desk +中華風TVセット=Chinese-Style TV Set +中華風シーリングライト=Chinese-Style Ceiling Light +中華風チェスト=Chinese-Style Chest +中華風テーブル=Chinese style table +中華風パソコンデスク=Chinese-Style Computer Desk +中華風フロアマット=Chinese-Style Floor Mat +中華風ベッド=Chinese-Style Bed +中華風丸テーブル=Chinese-Style Round Table +中華風壁=Chinese-Style Wall +中華風壁面ラック=Chinese-Style Wall Rack +中華風壁飾り=Chinese-Style Wall Decoration +中華風屏風=Chinese-Style Folding Screen +中華風椅子=Chinese-Style Chair +中華風箪笥=Chinese-Style Chest Of Drawers +中華麺と割り箸=Chinese Noodles and Chopsticks +串のみ(おでん用)=Skewer Only (For Oden Dish) +丸=Circle +丸い水面_小=Small Water Surface (Circle) +丸オーナメント=Bauble +丸テーブル高=Tall Circular Table +丸ハイライト=Circle Highlight +丸刈り=Buzz Cut +丸吹き出し1右=Oval 1 Right +丸吹き出し1右(影あり)=Oval 1 Right (Shadowed) +丸吹き出し1左=Rounded 1 Left +丸吹き出し1左(影あり)=Oval 1 Left (Shadowed) +丸吹き出し2右=Oval 2 Right +丸吹き出し2右(影あり)=Oval 2 Right (Shadowed) +丸吹き出し2左=Oval 2 Left +丸吹き出し2左(影あり)=Oval 2 Left (Shadowed) +丸吹き出し3右=Oval 3 Right +丸吹き出し3右(影あり)=Oval 3 Right (Shadowed) +丸吹き出し3左=Oval 3 Left +丸吹き出し3左(影あり)=Oval 3 Left (Shadowed) +丸吹き出し4右=Oval 4 Right +丸吹き出し4右(影あり)=Oval 4 Right (Shadowed) +丸吹き出し4左=Oval 4 Left +丸吹き出し4左(影あり)=Oval 4 Left (Shadowed) +丸型シーリングライト=Round Ceiling Light +丸型腕時計(桃)=Round watch (peach) +丸型腕時計(黒)=Round watch (black) +丸太=Wood Log +丸影=Circular Shadow +丸影改=Round Shading +丸椅子=Stool +丸椅子(高)=Stool (High) +丸照明1=Round lighting 1 +丸照明2=Round lighting 2 +丸瓶底眼鏡=Thick Circle Glasses +丸薄型シーリングライト=Round Thin Ceiling Light +主人公=Takeru +主人公のサンプルテキスト=Player's Sample Text +主人公のフォント=Player's Font +主人公の体型=The hero's body type +主人公の体型を変更します=I will change the body type of the main character +主人公の声の高低を設定します=Set the Pitch of Takeru's voice +主人公の服装=The main character's dress +主人公の服装を変更します=I will change the dress of the main character +主人公の表示を変更します=Change the display of the main character +主人公の音量を設定します=Set the volume of Takeru +主砲塔=Main turret +主砲身=Main barrel +乗馬ムチ=Riding Whip +乗馬鞭=Riding Crop +乙姫=Otome +乙姫の羽衣(色)=Otome no Omari (color) +乙姫の羽衣(色変え可能)=Princess Robe (Custom Color) +乳輪=Areola +乳輪の大きさ=Areola Size +乳輪の膨らみ=Areola Puffiness +乳首=Nipples +乳首クリップ=Nipple Clip +乳首スライダー=Nipple size +乳首のツヤ強さ=Nipple Gloss +乳首の太さ=Nipple Thickness +乳首の尖り具合=Nipple sharpness +乳首の種類=Nipple Type +乳首の色=Nipple Color +乳首の設定=Nipples +乳首パーツ=Nipple detachable +乳首リング=Nipple Ring +乳首リングジュエル=Jeweled Nipple Ring +乳首ローター=Nipple Rotor +乳首勃起=Nipple Erection +乳首太さ=Nipple Width +乳首洗濯ばさみ=Nipple Clothespin +乳首立ち=Nipple Depth +乳首舐め手コキ=Nipple Licking Fellatio +亀甲ライン=Turtle arm line +亀甲縛り=Turtle restraint +亀甲花菱=Turtleshell Flowers +亀頭いじり=Glans Rubbing +事件=Incident +事務棚1=Office Shelf 1 +事務棚2=Office Shelf 2 +事務棚3=Office Shelf 3 +事務棚4=Office Shelf 4 +事務棚5=Office Shelf 5 +事務棚6=Office Shelf 6 +事務棚7=Office Shelf 7 +事後=Afterglow +事後待機=Standby Afterwards +二丁拳銃=Dual Handgun +二丁拳銃1=Twin Pistols 1 +二丁拳銃2=Twin Pistols 2 +二丁拳銃3=Twin Pistols 3 +二対多角形(キャラ)=Notched Hexagon (Character) +二対多角形(通常)=Notched Hexagon (General) +二筋の傷=Two lines of scratches +二連ネックレス(色)=Dual necklace (color) +二郎=KG2 Jirou Stew +二重01=Double 01 +二重02=Double 02 +二重03=Double 03 +二重04=Double 04 +互い弄りA=Mutual Groping A +互い弄りB=Mutual Groping B +五右衛門風呂=Goemonmokuro Bath +五右衛門風呂(蓋)=Goemonmokuro (lid) +五右衛門風呂(踏み蓋)=Goemonmokuro (stepping lid) +五角形(キャラ)=Pentagon (Character) +五角形(通常)=Pentagon (General) +五角横台形(キャラ)=Horizontal Pentagon (General) +五角横台形(通常)=Horizontal Pentagon (General) +五連縦長窓=[PCM] Five-row Vertical Window +井戸(ポンプ)=Well (Pump) +亜依=Ai +人気順に並べる=Sort by popularity +仕切り=Dividers +仕切りカーテン=Privacy Curtain +付け三つ編み(色)=Braid braid (color) +付け毛ウェーブ=Bristle Wave +付け毛ウェーブ(色)=Wig hair (color) +付け毛お団子=Hair attached dumpling +付け毛お団子(色)=Dangling hair dumplings (color) +付け毛ストレート=Straight hair +付け毛ストレート(色)=Straight hair (color) +付け毛ツインテ1=Hair hair twin 1 +付け毛ツインテ1(色)=Attached hair twinte 1 (color) +付け毛ツインテ2=Attached hair twins 2 +付け毛ツインテ2(色)=Hair hair twin 2 (color) +付け毛ねじねじ=Hair screw thread +付け毛ねじねじ(色)=Hair screw thread (color) +付け毛の種類=Ahoge Type +付け毛ポニテ=Ponto hair attached +付け毛ポニテ(色)=Ponto hair (color) +付け毛太い=Attached hair thick +付け毛太い(色)=Attached hair thick (color) +付け毛細い=Attached hair thin +付け毛細い(色)=Attached hair thin (color) +付属アイテム表示=Show Attached Items +付着精液=Adhesion semen +仰向け=Looking Upward +仰向け愛撫=Caress (floor) +任意=Image +任意カメラ①記録無し=Optional camera ① No recording +任意カメラ②記録無し=Optional camera ② No record +任意カメラ③記録無し=Without any camera ③ record +休憩=Break +休日=Holidays +会話=Conversation +会話1=Conversation 1 +会話2=Conversation 2 +会話時間のないキャラを立ち止まらせない=Don't Stop Characters Who Can't Talk +会釈=Bow With Dish +伝説の剣=Legendary Sword +伸び=Stretching +位置=Position +位置X=X Location +位置Y=Y Location +位置Z=Z Location +位置変更時のリセット=Reset at location change +位置調整=Position +位置調整をそのままコピー=Copy position adjustment intact +位置調整を上下反転コピー=Position adjustment Upside-down copy +位置調整を左右反転コピー=Position adjustment Horizontal reversal copy +低=Low +低い=Lean +体=Body +体のプリセット=Body Presets +体の簡易設定=Simplified Body Settings +体の詳細設定=Advanced Body Settings +体位=Position +体位変更時のリセット=Reset at position change +体力=Power +体力増加(+10)カウンター=HP(+10) [Counter] +体力増加(+20)射程延長(+2)=HP(+20) Range(+2) +体勢の変更=Change of position +体型=Body +体型スライダー=Figure slider +体型の設定=Body Adjustments +体型をお手軽に設定=Enable Simple Body Settings +体操服=Gym suit wearing +体操着=Gym Uniform +体操着(水)=Gym clothes (water) +体操着(紺)=Gym clothes (navy) +体操着(赤)=Gym clothes (red) +体毛=Body hair +体温計=Thermometer +体育倉庫=Gym Storehouse +体育館=Gymnasium +体育館ライブ=Live Gymnasium Concert +体育館壁=Gym Wall +体育館床=Gym Floor +体重計=Weight Scale +作成日時=Creation Time +例のステージ=KG2 Example Stage +便器1=Toilet 1 +便器2=Toilet 2 +便器3=Toilet 3 +便器4=Toilet 4 +便所サンダル=Bathroom Sandals +保健室=School Infirmary +保健室ベッド=School Bed +保存=Save +保存して終了=Save and Exit +保存しないで終了=Exit Without Saving +保存するファイル名を入力してください=Name +保存せず終了=Cancel +保存をやめる=Don't Save +修道服=Friendship clothes +修道服(色)=Friary clothing (color) +修道服(色変え可能)=Nun Robe (Custom Color) +個性=Traits +倒れる=Knocked Down +値をコピー=Copy Value +値を貼り付け=Paste Value +偃月刀=Scimitar +側位=Spooning +側位(抵抗)=Lateral (resistance) +側位(脱力)=Side position (weakness) +側位(豹変)=Lateral position (latency change) +傘=Umbrella +傷ついた律子=Wounded Ritsuko +傷ついた明子=Wounded Akiko +傷ついた雪子=Wounded Yuko +優しい=Amiable +元に戻す=Undo +元気=Energetic +元気な女の子と会話=Conversation With Energetic Girl +先いじり=Tapping +先なし吹き出し(四角1)=No Tip (Rectangular 1) +先なし吹き出し(四角2)=No Tip (Rectangular 2) +先なし吹き出し(楕円1)=No Tip (Ellipse 1) +先なし吹き出し(楕円2)=No Tip (Ellipse 2) +先なし吹き出し(正円)=No Tip (Circular) +先なし吹き出し(角)=No Tip (Angular) +先なし吹き出し(雲)=No Tip (Cloud) +先上下=Chin Height +先前後=Chin Depth +先尖り棒(キャラ)=Pointed Rod (Character) +先尖り棒(通常)=Pointed Rod (General) +先幅=Chin Width +先舐め+竿舐め=Tip & Shaft Licking +光1=Light 1 +光10=Light 10 +光2=Light 2 +光3=Light 3 +光5=Light 5 +光6=Light 6 +光7=Light 7 +光8=Light 8 +光9=Light 9 +光のぼかし=Light Gradation +光の色=Light Color +光の鎧=Light Armor +光源=Light Source +兎萌=Rabbit Moe +兎萌デフォ=Rabbit Moe Default +兎萌設定読込=Read Rabbit Moe setting +入った時の状態に戻す=Revert to the Original State +入れてね=Put it in +入れるよ=I'm putting it in +入れ替え=Replace +入れ歯=Dentures +入れ歯(色)=Denture +全キャラを転校させますか?=Transfer all to a different school? +全て=Everything +全てチェック=Check All +全てデフォルト=All Default +全ての投稿者=All contributors +全ての投稿者のキャラをみる=See the characters of all contributors +全てリセット=Reset All +全て付ける=Wear All +全て外す=Remove All +全て空席にする=Empty All +全て表示=Show all +全て読込み=Load All +全て非表示=Hide all +全ビジュアル表示=Play All Visuals +全ビジュアル非表示=Don't Play Visuals +全体=Overall +全体1=Overall 1 +全体2=Overall 2 +全体の陰影の色=Overall Shadow Color +全体上下=Nose Height +全体光=Entire Map +全体光(ALL)=Overall light (ALL) +全体光(キャラのみ)=Overall light (character only) +全体光(マップのみ)=Overall light (map only) +全体前後=Nose Projection +全体塗り=Overall paint +全体強調=Overall emphasis +全体横幅=Overall width +全体角度X軸=Nose Angle +全体詳細=Overall Details +全体陰影=Overall shadow +全削除=Delete All +全員の音声の音量を調整します=Adjust the sound volume of everyone +全般=General +全表示=Show All +全裸=Naked +全裸全着=Fully nude +全解除=None +全身アザ(多)=Whole body aza (multiple) +全身アザ(少)=Whole body aza (little) +全身タイツ=Full-Body Tights +全身タイツハーフ(色)=Full body tights half (color) +全身タイツハーフ(色変え可能)=Fullbody Tights Half (Custom Color) +全身タイツロング(色)=Full body tights long (color) +全身タイツロング(色変え可能)=Fullbody Tights Long (Custom Color) +全選択=All +八角形(キャラ)=Octagon (Character) +八角形(通常)=Octagon (General) +八重歯=Double tooth +八重歯を表示する=Enable Fangs +公交车01=Bus 01 +公交车02=Bus 02 +公園=Park +公園(夕)=Park (evening) +公園(夜:消灯)=Park (night: lights off) +公園(夜:点灯)=Park (night: lit) +公園(昼)=Park (day) +公園(脱力)=Park (weakness) +公園(豹変)=Park (reversal) +公衆トイレ=Public Bathroom +公衆電話=Payphone +公鸡=Rooster +六花前髪=Rokka Bangs +六角形(キャラ)=Hexagon (Character) +六角形(通常)=Hexagon (General) +具合わせA=Scissoring A +具合わせB=Scissoring B +内ハネセミショート=Inner honey semi short +内ハネロング=Inner Hone Long +内側形状=Inner Arching +内履き=Indoors +内履きの色01=Indoor Shoe 01 Color +内履きの色02=Indoor Shoe 02 Color +内履きの色03=Indoor Shoe 03 Color +内履きを初期の状態に戻す=Restore Default Indoor Shoe Settings +内履き柄の色01=Indoor Shoe Pattern 01 Color +内履き柄の色02=Indoor Shoe Pattern 02 Color +内履き柄の色03=Indoor Shoe Pattern 03 Color +内巻きセミショート=Inner volume semi-short +円形横台形(キャラ)=Horizontal Circle (General) +円形横台形(通常)=Horizontal Circle (General) +円柱=Disc +円柱(溝あり)=Disc (Grooved) +円柱(細)=Rod +冥府の符術師=The Master of the Netherworld +冥騎士正装=Dark Knight Dress +冥騎士正装(武器有)=Dark Knight Dress (With Weapon) +冬用コート=Winter Coat +冬用ブーツ=Winter Boots +冬通学=Winter School Outfit +冷水器1=Water Fountain 1 +冷水器2=Water Fountain 2 +冷蔵庫=Refrigerator +凛花=Rika +几帳面=Diligent +処女=Virgin +出会い=Encounter +出席名簿=Attendance List +出来心=Sudden Impulse +刀=Sword +刀の鞘=Sword Scabbard +分娩台=Gyno Chair +切ない=Pained +切りっぱなし=Untrimmed +切り株=Tree Stump +刚铎剑=Rigidity +刚铎剑鞘=Rustic Sheath +刚铎盾=Rigid Shield +刚铎长枪=Long Spear +初めて=1st Time +初回H緩和=Always Virgins +初回律子=First time Riko +初回明子=First time Akiko +初回雪子=First time Yukiko +初対面=First meeting +初期=Inital +初期の親を設定=Inital Pos +初期ポーズ=T-Pose +初期値=Initial value +初期化=Reset +初期化しました=Scene reset. +初期化しますか?=Restore Defaults? +判定+1反撃=Decision +1 Counterattack +判定+1装甲+5=Decision +1 Armor +5 +判定+2=Decision +2 +判定+2発数×2=Decision +2 #Attacks×2 +判定+2装甲+3反撃=Decision +3 Armor +3 Counterattack +判定+3=Decision +3 +別れ=Farewell +別れる=Break up +利用規約=Terms of service +利用規約の確認=Confirmation of Terms of Service +制御パネル=Control +削除=Delete +前おさげ=Twintail Bangs +前へ=Prev +前下がりボブ(右)=Low Parted Bob (R) +前下がりボブ(左)=Low Parted Bob (L) +前嫌がりループ=Before Dislike Loop +前待機=About To Begin +前後=Depth +前後左右移動=XY Coordinates +前方右ディフレクタ=Forward Right deflector +前方左ディフレクタ=Forward left Deflector +前結びシャツ(桃)=Pre-knot shirt (peach) +前結びシャツ(白)=Front knotted shirt (white) +前結びデニム=Conclusion denim +前腕=Forearm +前面フレーム=Foreground +前面フレームを表示=Show Foreground Frame +前髪=Bangs +前髪と後ろ髪も同じ色に合わせる=Apply to Bangs & Back Hair +前髪と横髪も同じ色に合わせる=Apply to Bangs & Side Hair +前髪のアウトラインの色=Front Hair Outline Color +前髪の基本の色=Front Hair Base Color +前髪の根本の色=Front Hair Root Color +前髪の毛先の色=Front Hair Tip Color +前髪の種類=Front Hair Type +前髪の装飾の色01=Front Hair Accessory 01 Color +前髪の設定=Bangs +前髪の長さ=Front Hair Length +剣槍1=Sword Spear 1 +剣闘士=Gladiator +剣闘士の肩当て=Gladiator's shoulder rest +剣闘士の腕当て右用=Gladiator's arm's arm rest right: +剣闘士の腕当て左用=Gladiator 's Arm Left For Left +剣闘士の額当て=Gladiator's forehead rest +剣闘士ブーツサンダル=Gladiators Boots Sandals +剣闘士腕装具=Gladiator arm armor +剣闘士衣装=Gladiatorial costume +剣闘士衣装上=Gladiators on costume +剣闘士衣装下=Below the gladiator costume +割り箸=Disposable Chop +効果音=SFX +効果音の音量を設定します=Set the volume of sound effects +効果音量=Effect sound volume +勉強しよう=Study +勉強する?=Does Their Studies? +勉強をする=Studying +勉強をする待機=About To Study +動き回る=Moving Around +動き回る1=Moving Around 1 +動き回る2=Moving Around 2 +動き回る3=Moving Around 3 +動き回る4=Moving Around 4 +動き回る5=Moving Around 5 +動く波動=Energy Waves +動物は好き?=Likes Animals? +勝ち気=Willful +勝利確定=Victory +勤勉=Diligent +勾玉の首飾り=Magatama Amulet +包丁=Kitchen Knife +包帯=Bandage +包帯(色)=Bandage (color) +包帯コスチューム=Bandage costume +化粧=Makeup +化粧(基本)=Makeup +化粧の設定=Makeup Settings +北=North +北2=North 2 +医療=Medical Care +十四年式拳銃=German Type14 Pistol +十字(キャラ)=Cross (Character) +十字(通常)=Cross (General) +十字弩=Crossbow +十字弩箭=Crossbow Bolt +千代紙=Chiyogami Pattern +千紗=Chisa +千鳥格子=Hound's Tooth +半カプセル(キャラ)=Half Capsule (Character) +半カプセル(通常)=Half Capsule (General) +半コーン(キャラ)=Half Cone (Character) +半コーン(通常)=Half Cone (General) +半ピラミッド(キャラ)=Half Pyramid (Character) +半ピラミッド(通常)=Half Pyramid (General) +半円(キャラ)=Semicircle (Character) +半円(通常)=Semicircle (General) +半圆线(粉)=Semicircle Wire (Pink) +半圆线(黑)=Semicircle Wire (Black) +半月=Half Moon +半脱=Half +半袖とハーフパンツ=Short sleeve and half pants +半開きパーカー=Partially-Open Parka +卓上正常位=Desk Missionary +南=South +南2=South 2 +単純=Simple +単色=Solid Color +単色化=Monocolor +単色表示の色=Monochromatic Color +印=Emblem +危険日=Risky Day +卵(複数)=Egg (Multiple) +厚手パンストA=Thick Pantyhose A +厚手パンストB=Thick Pantyhose B +原点=Origin +参観者=Guest +友達=Friend +双眼鏡=Binoculars +双翼=Twin wings +反応好き=Loves Servicing +反撃=Counterattack +反映して終了=Apply & End +反映せず終了=Cancel & End +反転=Turn +反響などの音響効果の有無を設定します=Set the presence or absence of acoustic effects such as reverberation +取得効果=Ability Effect +受け流し・判定+2=Ward Off +受け皿=Drink Saucer +受け身=Passive +受け返し=Riposte +口=Mouth +口のパターン=Mouth Pattern +口の上下=Mouth Vertical Position +口の前後=Mouth Depth +口の形状上=Upper Lip Depth +口の形状下=Lower Lip Depth +口の形状口角=Mouth Corner Shape +口の横幅=Mouth Width +口の調整=Mouth Adjustments +口の開き=Mouth Openness +口の開き具合=Mouth Opening +口パク=Lip-Sync +口上下=Mouth Height +口元(右)=Mouth (right) +口元(左)=Mouth (left) +口元1=Mouth 1 +口内待機=Come In Mouth Idle +口内待機IN=Come In Mouth +口出し(ベース待機)=Withdrawal (base wait) +口出し(大ビク)=Escape (big) +口出し(小ビク1)=Outlet (Small Bikes 1) +口出し(小ビク2)=Outlet (small bik 2) +口出し待機=Outgoing standby +口前後位置=Mouth Projection +口当て布(色)=Portable cloth (color) +口形状上=Upper Lip Thickness +口形状下=Lower Lip Thickness +口形状口角=Corner Shape +口枷=Mouth hold +口横幅=Mouth Width +口汁見せ=Show juice +口紅=Lipstick +口紅カラー=Lipstick color +口縦幅=Lip Thickness +古い順=Oldest order +古い順に並べる=Oldest first +古や村(吊橋)=Old Village (Suspension Bridge) +古や村(吊橋・落)=Old Village (Suspension Bridge · Fall) +古や村(田んぼ)冬=Oyasumura (Rice Field) Winter +古や村(田んぼ)秋=Furu Oshimura (Tanbo) Autumn +古や村(裏山)=Oshayasura (Okuyama) +古や村(裏山)冬=Oriya Village (Bokuyama) Winter +古や村(裏山)秋=Furuya Village (Baishan) Fall +古や村(谷)=Old Village (Valley) +古や村(集落)冬=Old Village (Winter) +古や村(集落)春=Old Village (Spring) +古式ライフル銃=Flintlock Rifle +古式ライフル銃(色)=Ancient rifle (color) +古式銃=Flintlock Pistol +古式銃(色)=Old style gun (color) +台形1(キャラ)=Trapezoid 1 (Character) +台形1(通常)=Trapezoid 1 (General) +台形2(キャラ)=Trapezoid 2 (Character) +台形2(通常)=Trapezoid 2 (General) +右=Right +右スネ=Right Shin +右の口上=Right mouth above +右の口元=Right mouth +右の明るさ補正=Brightness Right pupil +右の目元=Right eyes +右の瞳=Right Pupil +右の瞳孔の開き=Right Pupil opening +右の色=Right Pupil color +右ひざ=Right Knee +右ひじ=Right Elbow +右ふくらはぎ=Back Of Right Calf +右上=Right and Up +右上腕=Right Upper Arm +右下=Down and Right +右中指=Right middle finger +右乳首=Right nipple +右人差指=Right index finger +右前腕部=Right Forearm Group +右太もも=Right Thigh +右尻=Right Buttcheek +右手=Right hand +右手のパターン=Right Hand Pattern +右手首=Right wrist +右目=Right Eye +右目の設定=Right Eye +右目の設定を左目に反映=Copy Right Eye To Left +右目も同じ色に合わせる=Apply to Right Eye +右耳=Right ear +右肩=Right shoulder +右胸操作=Right Breast +右脚=Right leg +右脚裏=Back Of Right Leg +右腕=Right arm +右舷前エレベータ=Forward Starboard Elevator +右舷後エレベータ=Rear Starboard Elevator +右薬指=Right third finger +右足=Right Foot +右足首=Right ankle +右頬=Right Side of Face +吉他(兔兔)=Instrument_09 +吉他(异型白)=Instrument_13 +吉他(异型绿)=Instrument_12 +吉他(木质)=Instrument_07 +吉他(火焰)=Instrument_11 +吉他(音符)=Instrument_08 +吉他(黑猫)=Instrument_10 +吊りパイプ固い=Stiff Hanging Pipe +吊りパイプ固い(長=Stiff Hanging Pipe (Long) +吊りパイプ柔らか=Flexible Hanging Pipe +吊りパイプ柔らか(長=Flexible Hanging Pipe (Long) +吊りボール固い=Stiff Hanging Ball +吊りボール固い(長=Stiff Hanging Ball (Long) +吊りボール柔らか=Flexible Hanging Ball +吊りボール柔らか(長=Flexible Hanging Ball (Long) +吊るし挿入=Hanging +吊るし挿入2=Hanging 2 +吊るし檻=Hanging Cage +同時絶頂=Simultaneous cum +同時絶頂(ベース待機)=Simultaneous cum (base standby) +同時絶頂(大ビク)=Simultaneous cum (big bike) +同時絶頂(小ビク1)=Simultaneous cum (small bike 1) +同時絶頂(小ビク2)=Simultaneous cum (small bik 2) +同時絶頂弱ループ=Mutual Weak Climax Loop +同時絶頂弱開始=Mutual Weak Climax Start +同時絶頂強ループ=Mutual Strong Climax Loop +同時絶頂強開始=Mutual Strong Climax Start +名=F +名前=Name +名前(昇順)=Name (Ascending) +名前(降順)=Name (Descending) +名前:=Name: +名前と性格=Name & Personality +名前と性格の設定=Name & Personality +名前の設定=Change Name +名前を入力=Enter A Name +名前を入力して下さい=Please Enter A Name +名前順=By name +吐いてね=Spit it +吐かせる=Spit out +吐き出し=Spit +吐き出し待機=Spit waiting +向きX=Direction X +向きY=Direction Y +向きZ=Direction Z +否定=Denial +吸血鬼=Vampire +吹き出し=Speech Balloons +吹き出しA=Balloon A +吹き出しB=Balloon B +吹き出しC=Balloon C +吹き出しD=Balloon D +吹き出しE=Balloon E +吹き出しF=Balloon F +吹き出しG=Balloon G +吹き出しH=Balloon H +吹き出し先1=Tip 1 +吹き出し先10=Tip 10 +吹き出し先2=Tip 2 +吹き出し先3=Tip 3 +吹き出し先4=Tip 4 +吹き出し先5=Tip 5 +吹き出し先6=Tip 6 +吹き出し先7=Tip 7 +吹き出し先8=Tip 8 +吹き出し先9=Tip 9 +呆れ=Amazed +告白/回想=Confession / Reflection +告白する=Confess +呪力=Curse +呼び出し=Calling Someone +命=Life +命令されたい=Obedient +和=Calm +和伞(吊兰)=Umbrella_03 +和伞(墨竹)=Umbrella_08 +和伞(樱开)=Umbrella_05 +和伞(樱舞)=Umbrella_06 +和伞(比翼)=Umbrella_11 +和伞(碎花)=Umbrella_04 +和伞(紫藤)=Umbrella_02 +和伞(红梅)=Umbrella_09 +和伞(缤纷)=Umbrella_07 +和伞(花坞醉归)=Umbrella_20 +和伞(花簇红)=Umbrella_14 +和伞(花簇青)=Umbrella_15 +和伞(花舞粉)=Umbrella_12 +和伞(花舞紫)=Umbrella_13 +和伞(花鸟)=Umbrella_10 +和伞(蛇目)=Umbrella_01 +和伞(青花山水)=Umbrella_19 +和伞(青花牡丹)=Umbrella_18 +和伞(青花诗)=Umbrella_17 +和伞(龙凤纹)=Umbrella_16 +和傘=Umbrella +和室=Japanese style room +和室(夕)=Japanese style room (evening) +和室(夜:消灯)=Japanese style room (night: lights off) +和室(夜:点灯)=Japanese style room (night: lighting) +和室(抵抗)=Japanese style room (resistance) +和室(昼)=Japanese-style room (day) +和室(脱力)=Japanese style room (weakness) +和室壁=Japanese-Style Wall +和照明1=Japanese lighting 1 +和色紙額=Sum Colored Paper Amount +和風シーリングライト=Japanese-Style Ceiling Light +和風ソファ=Japanese-Style Sofa +和風長椅子1=Japanese Chair 1 +和風長椅子2=Japanese Chair 2 +咖喱棒=Saber Excalibur +咥え=Hold In Mouth +咥え前待機=Standby before hanging +咥え型ヘッド=Squid Misc 1 +咥え型ヘッド(2色)=Tongue-Shaped Head (2CC) +咥え待機=Handle wait +咳き込み=Coughing +咳き込み待機=Cough cramps standby +哀1=Sad 1 +哀10=Sad 10 +哀2=Sad 2 +哀3=Sad 3 +哀4=Sad 4 +哀5=Sad 5 +哀6=Sad 6 +哀7=Sad 7 +哀8=Sad 8 +哀9=Sad 9 +唇=Lips +唇のツヤの強さ=Lip Gloss +唐草=Arabesque +喘ぎ1=Panting 1 +喘ぎ2=Panting 2 +喘ぎおっとり=Pant (Gentle) +喘ぎツンデレ=Pant (Tsundere) +喘ぎボーイッシュ=Pant (Boyish) +喘ぎヤンデレ=Pant (Yandere) +喘ぎ元気=Pant (Energetic) +喘ぎ几帳面=Pant (Diligent) +喘ぎ大雑把=Pant (Easygoing) +喘ぎ妖艶=Pant (Bewitching) +喘ぎ明るい=Pant (Cheerful) +喘ぎ活発=Pant (Active) +喘ぎ無口=Pant (Withdrawn) +喘ぎ生真面目=Pant (Strict) +喘ぎ誠実=Pant (Sincere) +喜1=Happy 1 +喜10=Happy 10 +喜2=Happy 2 +喜3=Happy 3 +喜4=Happy 4 +喜5=Happy 5 +喜6=Happy 6 +喜7=Happy 7 +喜8=Happy 8 +喜9=Happy 9 +喜び=Pleased +喪服(色変可能)=Mourning Dress (CC) +喪服(黒)=Mourning Dress (Black) +喪服洋服(色)=Mourning clothes (color) +喪服着物(色)=Mourning kimono (color) +四つん這い=Hands & Knees +四つん這い愛撫=Caress (all fours) +四分円(キャラ)=Quadrant (Character) +四分円(通常)=Quadrant (General) +四季の窓(夏)=Seasonal Windows (Summer) +四季の窓・冬=[PCM] Season Window Winter +四季の窓・春=[PCM] Season Window Spring +四季の窓・秋=[PCM] Season Window Fall +四角=Rectangular +四角い水面_小=Small Water Surface (Square) +四角テーブル=Rectangular Table +四角ハイライト=Square Highlight +四角吹き出し1右=Rectangular 1 Right +四角吹き出し1右(影あり)=Rectangular 1 Right(Shadowed) +四角吹き出し1左=Rectangular 1 Left +四角吹き出し1左(影あり)=Rectangular 1 Left (Shadowed) +四角吹き出し2右=Rectangular 2 Right +四角吹き出し2右(影あり)=Rectangular 2 Right (Shadowed) +四角吹き出し2左=Rectangular 2 Left +四角吹き出し2左(影あり)=Rectangular 2 Left (Shadowed) +四角型シーリングライト=Square Ceiling Light +四角照明=Square lighting +回復=Recovery +回想=Recollection +回想吹き出し1右=Thinking 1 Right +回想吹き出し1右(影あり)=Thinking 1 Right (Shadowed) +回想吹き出し1左=Thinking 1 Left +回想吹き出し1左(影あり)=Thinking 1 Left (Shadowed) +回転=Rotator +回転X=X Rotation +回転Y=Y Rotation +回転Z=Z Rotation +回転軸のリセット=Rotation axis reset +回転速度=Rotational speed +回転量=Rotation Amount +回転音=Rotation +回避2=Evasion 2 +困り=Worried +困る=Worried +囲炉裏=Sunken Fireplace +図書室=Library +図書室棚1=Library Shelf 1 +図書室棚2=Library Shelf 2 +図書室棚3=Library Shelf 3 +図書室棚4=Library Shelf 4 +図書室棚5=Library Shelf 5 +図書室棚6=Library Shelf 6 +固定=Fixed +固定エフェクト=Fixed Effects +固定ギロチン=Fixed Guillontine +固定ギロチン(ハニー)=Fixed Guillotine (Honey) +圆头钩=Round Head Hook +土下座弄り=Prostated Fingering +土下座愛撫=Akashi Kimaeda +土制炸弹=Improvised Explosive Device +土台1=Base 1 +土台2=Base 2 +土堆=Mound +土星=Saturn Earring +土星のペンダント=Saturn Pendant +地下室=Basement +地下室(夕)=Basement (evening) +地下室(夜:消灯)=Basement (night: lights off) +地下室(夜:点灯)=Basement (night: lighting) +地下室(抵抗)=Basement (resistance) +地下室(昼)=Basement (day) +地下室(脱力)=Basement (weakness) +地図=Map +地狱火马=Hellfire Horse +地球儀=Globe +地面=Ground +地面(コンクリ)=Ground (Concrete) +地面(タイル1)=Ground (Tile 1) +地面(タイル2)=Ground (Tile 2) +地面(土)=Dirt +地面(木1)=Ground (Wood 1) +地面(木2)=Ground (Wood 2) +地面(石1)=Ground (Stone 1) +地面(石2)=Ground (Stone 2) +基本=Basic +基本となる視野角の角度を設定します=Set the angle of the basic viewing angle +基本図形:キューブ=Basic figure: Cube +基本図形:クリスタル=Basic figure: Crystal +基本図形:コーン=Basic figure: Cone +基本図形:シリンダー=Basic figure: cylinder +基本図形:ピラミッド=Basic figure: pyramid +基本図形:リング=Basic figure: Ring +基本形=Models +場所=Place +境界線=Boundary Lines +境界線のある影=Boundary Line Shadows +壁=Walls +壁(コンクリ1)=Wall (Concrete 1) +壁(コンクリ2)=Wall (Concrete 2) +壁(レンガ)=Wall (Brick) +壁(土1)=Wall (Soil 1) +壁(土2)=Wall (Soil 2) +壁(抵抗)=Wall (resistance) +壁(木1)=Wall (Wood 1) +壁(木2)=Wall (Wood 2) +壁(木3)=Wall (Wood 3) +壁(木4)=Wall (Wood 4) +壁(木5)=Wall (Wood 5) +壁(木6)=Wall (Wood 6) +壁(木7)=Wall (Wood 7) +壁(木8)=Wall (Wood 8) +壁(木9)=Wall (Wood 9) +壁(石1)=Wall (Stone 1) +壁(石2)=Wall (Stone 2) +壁(石3)=Wall (Stone 3) +壁(石4)=Wall (Stone 4) +壁(脱力)=Wall (weakness) +壁(豹変)=Wall (leaf change) +壁、床=Wall & Floor +壁バック=Doggystyle Against Wall +壁バックアナル=Anal Doggystyle Against Wall +壁バック愛撫=Caress (wall) +壁ボックス1=Wall Box 1 +壁ボックス2=Wall Box 2 +壁ボックス3=Wall Box 3 +壁側位=Wall Side-wards +壁対面片足上げ=Leg Lifted Facing Against Wall +壁掛け1=Wall Decoration 1 +壁掛け2=Wall Decoration 2 +壁棚=Wall Shelf +壁棚1=Wall Shelf 1 +壁棚2=Wall Shelf 2 +壁棚2=Wall shelf 2 +壁棚3=Wall shelf 3 +壁棚4=Wall shelf 4 +壁沿い=Against the Wall +壁立ち1=Leaning On Wall 1 +壁立ち2=Leaning On Wall 2 +壁立ち3=Leaning On Wall 3 +壁立ちバック=Against Wall Behind +壁電話&大小箪笥=Wall Phone And Chest of Drawers +壊れ=Broken +壮亮=Sosuke +声の出演=Voice appearance +声質=Voice +壺1=Vase 1 +壺1=Vase 1 +壺2=Vase 2 +壺2=Vase 2 +変則ストライプ=Irregular Vertical Stripes +変則ボーダー=Irregular Horizontal Stripes +変形まとめ=Slider List +変更して保存=New Image +変更せず保存=Keep Image +変更を戻して切り替え=Change back and switch +変更を戻して終了=Revert and Exit +変更を適用して切り替え=Apply changes and switch +変更を適用して終了=Apply changes and close +変異=Mutation +复合弓=Composite bow +复合弓(拉弦)=Composite Bow (Drawn) +夏の夕暮れ=Summer Twilight Chirping +夏音=Akane +夕=Evening +夕方=Evening +夕方の町並み=Evening Street +夕焼け=Evening +夕空=Twilight Sky +外に出すよ=I'm cumming outside +外ハネシャギー(前)=Outside Hanashagi (front) +外ハネシャギー(後ろ)=Outside Honeyshagi (behind) +外ハネショート=Outside honey short +外はねショート=Short, Swept Out +外ハネロング=Outside Hone Long +外はねロング=Long, Feathered Out +外を眺める=Looking Outside +外側形状=Outer Arching +外出し=Cum Outside +外出し(ベース待機)=Go out (base wait) +外出し(小ビク1)=Go out (small bike 1) +外出し(小ビク2)=Go out (small bik 2) +外出し(引き抜き)=Go out (withdraw) +外出し・引き抜き待機=Go out and wait for extraction +外出しループ=Come Outside Loop +外出し事後=Come Outside End +外出し開始=Come Outside Start +外履き=Outdoors +外履きの色01=Outdoor Shoe 01 Color +外履きの色02=Outdoor Shoe 02 Color +外履きの色03=Outdoor Shoe 03 Color +外履きを初期の状態に戻す=Restore Default Outdoor Shoe Settings +外履き柄の色01=Outdoor Shoe Pattern 01 Color +外履き柄の色02=Outdoor Shoe Pattern 02 Color +外履き柄の色03=Outdoor Shoe Pattern 03 Color +外灯=Outdoor Light +外観=Appearance +外部画像=Background +外部読込=Load External File +多=100 +多用途ヘリ(格納)=Multi-purpose helicopter (stored) +多用途ヘリ(飛行)=Multi-purpose helicopter (flight) +多用途ヘリ(駐機)=Multi-purpose helicopter (tarmac) +多目的トイレ=Multipurpose Restroom +夜=Night +夜(明)=Night(Lights on) +夜(暗)=Night(No Lights +夜(消灯)=Night (lights off) +夜(点灯)=Night (lit) +夜の町並み=Night Street +夜の窓=[PCM] Night Window +夜空=Night Sky +夜都市楼顶=Urban Roof +大=Large +大きい=Big +大きい海面_大きい波=Huge Sea Surface (Big Waves) +大きい海面_日差し有=Huge Sea Surface (Sunlight) +大きい海面_日差し無=Huge Sea Surface (No Sunlight) +大きさ=Size +大きさX=Size X +大きさY=Size Y +大きさZ=Size Z +大きなリボン=Large Ribbon +大きな和柄リボン(緑)=Large Japanese Pattern Ribbon (Green) +大きな和柄リボン(赤)=Big Japanese Pattern Ribbon (Red) +大人ワンピ(色)=Adult dress (color) +大人ワンピ(色変え可能)=Adult One-Piece (Custom Color) +大人ワンピ(黄)=Adult dress (Yellow) +大人ワンピ(黒)=Adult dress (black) +大人ワンピース=Adult One-Piece +大八車=Large Two-Wheeled Wagon​ +大剣1=Large Sword 1 +大和撫子=Yamato Nadeshiko +大型定規1=Large Ruler 1 +大型定規2=Large Ruler 2 +大型定規3=Large Ruler 3 +大小箪笥=Large and small chest of drawers +大根=Japanese Radish +大棚1=Large Shelf 1 +大棚2=Large Shelf 2 +大盾=Large Shield +大砲=Cannon +大砲(台)=Cannon (Stand) +大砲(玉)=Cannonball +大砲(筒)=Cannon (Barrel) +大縦長=Wide And Wispy +大老虎=Big Tiger +大雑把=Easygoing +天井=Ceiling +天使=Angel +天使の翼右用=Right Angel Wing +天使の翼左用=Left Angel Wing +天使の輪=Angel Halo +天狗の鼻(色)=Tengu's nose (color) +太い=Thick +太め=Thick +太め(中)=Thickened (medium) +太め(短)=Thick (short) +太め(長)=Thick (long) +太めのカーブ=Thick curve +太ももにぶっかけ=Bukkake on thighs +太もも上=Thighs +太もも上の奥=Upper Thigh Thickness +太もも上の幅=Upper Thigh Width +太もも下=Legs +太もも下の奥=Lower Thigh Thickness +太もも下の幅=Lower Thigh Width +太ロング=Thick Long +太縦長=Long And Wide +太腿上=Thighs +太腿下=Legs +太陽=The sun +夫婦の寝室=Couple's bedroom +夫婦の寝室(夕)=A couple's bedroom (evening) +夫婦の寝室(夜:消灯)=Couple's bedroom (night: lights off) +夫婦の寝室(夜:点灯)=A couple's bedroom (night: lighting) +夫婦の寝室(抵抗)=The couple's bedroom (resistance) +夫婦の寝室(昼)=A couple's bedroom (day) +夫婦の寝室(脱力)=The couple's bedroom (weakness) +奉仕=Service +奉仕(抵抗)=Service (resistance) +奉仕(脱力)=Service (weakness) +奉仕(豹変)=Service (change) +女=Woman +女2・W素股=2 Girl Pussy Grind +女2・手コキフェラ=2 Girl Handjob +女2・股間弄り=2 Girl Fingering +女2・騎乗位クンニ=2 Girl Cowgirl +女2A愛撫=Caress A (2G) +女2A手コキ=Handjob A (2G) +女2A素股=Frottage A (2G) +女2A騎乗位=Cowgirl A (2G) +女2B愛撫=Caress B (2G) +女2B手コキ=Handjob B (2G) +女2B素股=Frottage B (2G) +女2B騎乗位=Cowgirl B (2G) +女2愛撫=Caress (2G) +女2手コキ=Handjob (2G) +女2素股=Frottage (2G) +女2騎乗位=Cowgirl (2G) +女H奉仕=Girl Service +女H挿入=Girl Insertion +女カットイン=Female: Cut-In +女キャラ=Girls +女キャラ選択=Girl Selection +女の子好き=Likes Girls +女の子座り=Girly Sitting +女の子部屋=Girl room +女の子部屋前=Girl Room Front +女の子風ベッド=Girl-Style Bed +女ライフル=Female: Rifle +女両手剣=Female: Two-Handed Sword +女主導手コキ素股=Handjob Humping (Her Lead) +女主導椅子素股=Sitting Humping (Her Lead) +女主導背面騎乗=Reverse Cowgirl (Her Lead) +女主導騎乗=Cowgirl (Her Lead) +女主導騎乗素股=Cowgirl Humping (Her Lead) +女位置へ男を移動=Move Man To Girl +女剣闘士=Female sword fighter +女剣闘士衣装=Gladiator Costume +女子トイレ個室=Single Girl's Toilet +女小太刀1=Female: Short Sword 1 +女小太刀2=Female: Short Sword 2 +女弓矢=Female: Bow And Arrow +女性11A=Female 11A +女性11B=Female 11B +女性22A=Female 22A +女性22B=Female 22B +女性ボイス=Female Voices +女性器=Vagina +女投擲=Female: Throwing +女拘束=Woman Restraint +女拘束(脱力)=Woman restraint (weakness) +女拘束咥え=Woman Restraint Hold +女拘束咥え(抵抗)=Woman restraint hold (resistance) +女拘束尻コキ=Woman Restraint Butt Job +女拘束愛撫=Women Restraint +女拘束愛撫(抵抗)=Female restraint caress (resistance) +女拘束愛撫(脱力)=Lady restrained caress (weakness) +女拳銃1=Female: Pistol 1 +女拳銃2=Female: Pistol 2 +女格闘A=Female: Fighting A +女格闘B=Female: Fighting B +女棒・槍=Female: Polearm / Spear +女槌・鎌=Female: Hammer / Sickle +女気弾=Female: Energy Bullet +女水を掛けられる=Girl: Splashed By Water +女水を掛ける=Girl: Splashing Water +女海賊=Female pirate +女海賊衣装=Pirate Costume +女準備体操=Girl: Warm-Up Exercise +女片手剣=Female: One-Handed Sword +女生摩托车01=Girls Motorcycle 01 +女生摩托车02=Girls Motorcycle 02 +女盾と剣=Female: Sword And Shield +女神の戦衣・スカートA=Goddess's Battle Skirt A +女神の戦衣・スカートB=Goddess's Battle Skirt B +女神の戦衣・トップスA=Goddess's Battle Top A +女神の戦衣・トップスB=Goddess's Battle Top B +女絶頂=Woman cum +女絶頂弱ループ=Girl Weak Climax Loop +女絶頂弱開始=Girl Weak Climax Start +女絶頂強ループ=Girl Strong Climax Loop +女絶頂強開始=Girl Strong Climax Start +女豹ワンピース=Female leopard dress +女部屋風壁=Girl Room Wind Wall +女魔法本=Female: Grimoire +女魔法杖=Female: Magic Wand +好きかも=Affectionate +好みの子を探します=Girl Finder +好奇心=Curiosity +好意=Like +好意2=Like 2 +好意順=By affection +好感度=Affection +妊娠検査薬=Pregnancy Test +妖刀=Demon Blade +妖精の長靴=Fairy boots +妖精の靴=Fairy shoes +妖艶=Bewitching +姉御肌=Big Sisterly +姓=L +姫カット(右)=Princess Cut (R) +姫カット(左)=Princess Cut (L) +姿勢を変える1=Changing Posture 1 +姿勢を変える2=Changing Posture 2 +威力=Power +威力+30=Power +30 +婚約指輪=Engagement ring +婚約指輪(色)=Engagement ring (color) +媚薬=Aphrodisiac +嫌い=Loathing +嫌がりフェラ=Forced Fellatio +嫌がり手コキ=Handjob +嫌がり正常位=Forced Missionary +嫌悪=Hate +嫌悪2=Hate 2 +嬉しい=Happy (Broad) +嬉しいs=Happy (Moderate) +嬉しいss=Happy (Slight) +子宮=Vaginal Prolapse +字剃刀=Razor +学ラン(男)=Gakuran (Male) +学ランTシャツ(男)=Gakuran And T-Shirt (Male) +学ラン前開き=Gakuran (Opened) +学園名を入力して下さい=Please Enter the School's Name +学園長=Headmistress +学生服=School Uniform +学生服(下校)=Going Home +学生服(下校)=Going Home +学生服(校内)=In School +学生服(校内)=In School +学生証画像=Student Card Picture +学生証画像の撮影=Take Student ID Image +学生証画像を撮影=Student Card +宇宙空間01=Space 01 +宇宙空間02=Space 02 +宇宙空間03=Space 03 +宇宙空間04=Space 04 +安らぎ=Comfort +安全ピン=Safety Pin +安全日=Safe Day +完了=Done +完全なめらか影=Perfect, Smooth Shadows +定食1=Full Meal 1 +定食2=Full Meal 2 +定食3=Full Meal 3 +定食4=Full Meal 4 +定食5=Full Meal 5 +定食6=Full Meal 6 +宝石の指輪(色)=Jewelry ring (color) +宝箱=Treasure Chest +宝箱1=Treasure Chest 1 +宝箱2=Treasure Chest 2 +宝箱2=Treasure box 2 +宮殿=The Palace +家に帰りますか?=Go home? +家具=Furniture +容姿=Appearance +容姿と服読込み=Appearance and Clothes +容姿を確認する=Examining Self +容姿を確認する待機=About To Examine Self +容姿読込み=Load Appearance +寂しい=Lonely +寂しがり屋=Lonely +密着型ヘッドホン=Snug Headphones +寝=Laying +寝1=Laying 1 +寝1=Laying 1 +寝2=Laying 2 +寝2=Laying 2 +寝3=Laying 3 +寝3=Laying 3 +寝4=Laying 4 +寝4=Laying 4 +寝5=Laying 5 +寝5=Laying 5 +寝6=Laying 6 +寝7=Laying 7 +寝8=Laying 8 +寝オナニー=Sleep Masturbation +寝たふり=Pretending To Sleep +寝パイズリ=Boob Job - Laying +寝パイズリ(抵抗)=Lying Fucking (resistance) +寝パイズリ(脱力)=Female Tit Fiter (Weakness) +寝パイズリ(豹変)=Sleeping Fucking (Rabbit Change) +寝バック=Lying Doggystyle +寝ポーズ=Sleeping Pose +寝る=Sleep +寝咥え=Blowjob - Laying +寝咥え(脱力)=Sleepy grip (weakness) +寝咥え(豹変)=Sleeping sleepiness +寝手コキ=Handjob - Laying +寝手コキ(豹変)=Sleeping handjob (reversal change) +寝舐め=Licking - Laying +寝舐め(豹変)=Sleeping lick (聞 modification) +寝返り=Turning Over +寝返り1=Turning 1 +寝返り2=Turning 2 +寝返り待機=About To Turn Over +対面座位=Face to Face Sitting +寿司桶=Sushi Platter +射程+3=Range +3 +射程延長(+2)攻撃範囲化(+2)=Range(+2) AoE(+2) +射程延長(+3)根性=Range(+3) [Temper] +射精(ベース待機)=Ejaculation (base wait) +射精(大ビク)=Ejaculation (big) +射精(小ビク1)=Ejaculation (Small Bikes 1) +射精(小ビク2)=Ejaculation (Small Bikes 2) +射精して=Climax +将校のガーターベルト=Commissioned Officer Garter Belt +将校のサーベル=Commissioned Officer Sabre +将校のブーツ=Commissioned Officer Boots +将校の帽子=Commissioned Officer Hat +将校の手袋=Commissioned Officer Gloves +将棋盤=Shogi Board +将棋駒入れ=Shogi Piece Container +小=Small +小さい=Small +小三角=Small Triangle +小剣1=Small Sword 1 +小剣2=Small Sabre 2 +小剣3=Small Sabre 3 +小剣4=Small Sabre 4 +小太刀=Short Sword +小太刀(色)=Oota sword (color) +小太刀1=Short Sword 1 +小太刀2=Short Sword 2 +小太刀3=Short Sword 3 +小太刀二刀=Dual Kodachi +小太刀二刀1=Twin Short Swords 1 +小太刀二刀2=Twin Short Swords 2 +小太刀二刀3=Twin Short Swords 3 +小屋=Hut +小悪魔=Small Devil +小悪魔スカート=Devil Skirt +小悪魔チョーカー=Devil Choker +小悪魔トップス=Devil Top +小悪魔ニーソックス=Devil Kneesocks +小悪魔の翼右用=Right Devil Wing +小悪魔の翼左用=Left Devil Wing +小悪魔パンプス=Devil Pumps +小悪魔フォーク=Devil Pitchfork +小悪魔フォーク(小)=Devil Pitchfork (Small) +小悪魔尻尾=Devil Tail +小悪魔手袋=Devil Gloves +小木船=Small Boat (For Pirate Ship) +小棚1=Small Shelf 1 +小棚2=Small Shelf 2 +小棚3=Small Shelf 3 +小棚4=Small Shelf 4 +小棚5=Small Shelf 5 +小棚6=Small Shelf 6 +小棚7=Small Shelf 7 +小物=Small Articles +小物半透明=Small articles translucent +小物非表示=Hidden items +小盾=Small Shield +小美的刀鞘=Samurai Sword Sheath +小美的武士刀=Samurai Sword +小美的浴勺=ANG Shaozi +小美的浴缸=ANG Yugang +小美的玩具喵=ANG Miao +小舟(櫓)=Small Boat (Oar) +小舟(船体)=Small Boat (Hull) +小鸟直升机=AH6b Littlebird Heli +小鸟直升机(飞行)=AH6a Heli +小麦=Tan +小鼻上下=Nostril Height +小鼻前後=Nostril Length +小鼻横幅=Nose Width +小鼻角度X軸=Nostril Inner Width +小鼻角度Z軸=Nostril Outer Width +少=0 +尻=Butt +尻アザ=Ass Aza +尻コキ=Butt Job +尻コキ(脱力)=Buttjob (weakness) +尻コキ(豹変)=Buttjobi (reversal) +尻すぼみ=Buttocks +尻にぶっかけ=Bukkake on buttocks +尻のサイズ=Butt Size +尻の角度=Butt Angle +尻上がり=Tail rising +尻反応開始=Initial Butt Touch +尻尾=Tail +尻尾着脱=Toggle tail +尻穴=Anus +尻角度=Butt angle +尻触り待機=About To Grope Butt +尼尔机械纪元_2B=2B's Outfit (Neir Automata) +尿道=Urethral Prolapse +居酒屋板子一枚=Japanese Gastropub​ +屈脚位=Bent Missionary +屋上=Rooftop +屋根(木)=Roof (Wood) +屋根(瓦)=Roof (Tile) +属性=Element +屠龙=CF TL +山型多角形1(キャラ)=Mountain Polygon 1 (Character) +山型多角形1(通常)=Mountain Polygon 1 (General) +山型多角形2(キャラ)=Mountain Polygon 2 (Character) +山型多角形2(通常)=Mountain Polygon 2 (General) +山羊1=Goat 1 +山羊2=Goat 2 +岩1=Rock 1 +岩1=Rock 1 +岩2=Rock 2 +岩2=Rock 2 +岩3=Rock 3 +岩3=Rock 3 +岩4=Rock 4 +岩4=Rock 4 +岩5=Rock 5 +岩5=Rock 5 +峰鈴音=Takashi Suzune +島のラジオ=Island Radio +川=River +左=Left +左クリックで現在のカラーを登録します=Left-Click To Copy Current Color +左クリックで適用=Left-Click To Apply +左クリック移動=Left-Click To Move +左スネ=Left Shin +左の口上=Left mouth above +左の口元=Left mouth +左の明るさ補正=Brightness Left pupil +左の目元=Left eye +左の瞳=Left pupil +左の瞳孔の開き=Left Pupil Opening +左の色=Left Pupil color +左ひざ=Left Knee +左ひじ=Left Elbow +左ふくらはぎ=Back Of Left Calf +左上=Up and Left +左上腕=Left Upper Arm +左下=Down and Left +左中指=Left middle finger +左乳首=Left nipple +左人差指=Left index finger +左前腕部=Left Forearm Group +左右の明るさ補正=Brightness +左右の瞳=Both Pupils +左右の瞳孔の開き=Eye opening +左右の色=Both Eye whites +左右の親を入れ替え=Swap Sides +左右の親を切り替える=Swap Sides When Transfering +左太もも=Left Thigh +左尻=Left Buttcheek +左手=Left hand +左手のパターン=Left Hand Pattern +左手首=Left wrist +左目=Left Eye +左目の設定=Left Eye +左目の設定を右目に反映=Copy Left Eye To Right +左目も同じ色に合わせる=Apply to Left Eye +左耳=Left ear +左肩=Left shoulder +左胸操作=Left Breast +左脚=Left leg +左脚裏=Back Of Left Leg +左腕=Left arm +左舷後エレベータ=Forward Port Elevator +左薬指=Left ring finger +左足=Left Foot +左足首=Left ankle +左轮枪=Zuolun +左頬=Left Side of Face +巨乳=Busty +巨根H=Big Dick H +巫女スカート=Shrine Maiden Skirt +巫女ニーソックス=Shrine Maiden Kneesocks +巫女ニーソックス(色)=Maiden god knee socks (color) +巫女ニーソックス(色変え可能)=Miko Knee Socks (Custom Color) +巫女内衣=Shrine Maiden's Robe +巫女服=Shrine maiden wear +巫女服(ミニスカート)=Shrine maiden clothes (mini skirt) +巫女服ミニスカート(色)=Shrine maiden clothes miniskirt (color) +巫女服ミニスカート(色変え可能)=Miko Mini Skirt (Custom Color) +巫女服袴(色)=Shrine maiden hakama (color) +巫女服袴(色変え可能)=Miko Hakama (Custom Color) +巫女武者=Shrine Maiden +巫女武者手甲=Shrine Maiden Warrior Bracers +巫女狐=Maiden fox +巫女袖=Shrine Maiden Sleeve +巫女袖右用=Shrine Maiden Sleeve (Right) +巫女袖右用(色)=Shrine maiden sleeve right (color) +巫女袖左用=Shrine Maiden Sleeve (Left) +巫女袖左用(色)=Shrine maiden sleeve for left (color) +巻き角=Winding angle +巻き角(色)=Winding angle (color) +巻紙=Paperboard +巾着=Chikuwa +市松チェック=Checkerboard +布団=Futon +布団2=Futon 2 +布巾=Dressing width +布袋=Cloth Bag +带结绳子=Rope 1 +帯(喪服)=Obi (Mourning) +帯(着物)=Obi (Kimono) +帯ハイライト=Band Highlight +帰宅部=Going Home Club +帽子=Hat +平均台=Balance Beam +平行移動=Parallel Move +平面(キャラ)=Flat Plane (Character) +平面(通常)=Flat Plane (General) +平面液垂れA・透可=Dripping A · Clear +平面液垂れB・透可=Dripping B · Clear +年数Ⅰ=Year Ⅰ +年数Ⅱ=Year Ⅱ +年数Ⅲ=Year Ⅲ +広一=Koichi +広一の声の高低を設定します=Set the Pitch of Hiroichi voice +広一の音量を設定します=Set the volume of Hiroichi +床=Floor +床座り1=Floor Seating 1 +床座り2=Floor Seating 2 +床座り3=Floor Seating 3 +床拘束正常位=Floor Bondage Missionary +床拘束正常位2=Floor Bondage Missionary 2 +废黜君王的权杖=Dismissed The King's Scepter +座り=Sitting +座り1=Sitting 1 +座り1=Sitting 1 +座り10=Sitting 10 +座り11=Sitting 11 +座り2=Sitting 2 +座り2=Sitting 2 +座り3=Sitting 3 +座り3=Sitting 3 +座り4=Sitting 4 +座り4=Sitting 4 +座り5=Sitting 5 +座り5=Sitting 5 +座り6=Sitting 6 +座り6=Sitting 6 +座り7=Sitting 7 +座り7=Sitting 7 +座り8=Sitting 8 +座り8=Sitting 8 +座り9=Sitting 9 +座りパイズリ=Boob Job - Sitting +座りパイズリ(豹変)=Sitting fucking (change) +座りポーズ=Sitting Pose +座りポーズ1=Sitting Pose 1 +座りポーズ2=Sitting Pose 2 +座り咥え=Blowjob - Sitting +座り咥え(抵抗)=Sitting (resistance) +座り咥え(豹変)=Sitting (change) +座り壊れ=Broken Sitting +座り手コキ=Handjob - Sitting +座り手コキ(抵抗)=Sitting handjob (resistance) +座り手コキ(豹変)=Sitting handjob (leaf change) +座り舐め=Licking - Sitting +座り舐め(豹変)=Sitting licking (changeover) +座布団=Cushion +座布団(雪山温泉)=Cushion (Yukiyama Onsen) +座布団1=Zabuton 1 +座布団2=Zabuton 2 +座椅子=Legless Chair +座高計=Seated Height Scale +廃工場=Snooley Warehouse +廊下1F=Corridor 1F +廊下2F=Corridor 2F +廊下3F=Corridor 3F +建造物=Structures +开山刀=Kaiyama sword +开胸毛衣@saw=Keyhole Turtleneck @saw +弁当1=Bento 1 +弁当2=Bento 2 +弁当3=Bento 3 +弓=Bow +弓A=Bow A +弓A(拉弦)=Bow A (Drawn) +弓B=Bow B +弓B(拉弦)=Bow B (Drawn) +弓C=Bow C +弓C(拉弦)=Bow C (Drawn) +弓D=Bow D +弓D(拉弦)=Bow D (Drawn) +弓E=Bow E +弓E(拉弦)=Bow E (Drawn) +弓F=Bow F +弓F(拉弦)=Bow F (Drawn) +弓G=Bow G +弓G(拉弦)=Bow G (Drawn) +弓H=Bow H +弓H(拉弦)=Bow H (Drawn) +弓I=Bow I +弓I(拉弦)=Bow I (Drawn) +弓J=Bow J +弓J(拉弦)=Bow J (Drawn) +弓K=Bow K +弓K(拉弦)=Bow K (Drawn) +弓かけ=Archery Glove +弓矢=Bow +弓矢1=Bow And Arrow 1 +弓矢2=Bow And Arrow 2 +弓矢3=Bow And Arrow 3 +弓箭A=Arrow A +弓箭B=Arrow B +弓袋=Bow Bag +弓道衣=Archery Top +弓道衣胸当てなし=Archery Top Without Breastplate +弓道袴=Archery Skirt +引き抜き=Withdrawal +弥生のスカート(色)=Yayoi's skirt (color) +弥生のスカート(色変え可能)=Yayoi Skirt (Custom Color) +弥生のすね当て(色)=Yayoi's shimmering (color) +弥生のすね当て(色変え可能)=Yayoi Shin Guard (Custom Color) +弥生のリボン(色)=Yayoi's ribbon (color) +弥生の手甲(色)=Yayoi's armor (color) +弥生の手甲(色変え可能)=Yayoi Armor (Custom Color) +弥生の肩当て(色)=Yayoi's shoulder rest (color) +弥生の腰防具(色)=Yayoi waist armor (color) +弥生の衣装(色)=Yayoi's costume (color) +弥生の衣装(色変え可能)=Yayoi Outfit (Custom Color) +弥生の衣装防具無し(色)=Yayoi's costume no armor (color) +弥生の衣装防具無し(色変え可能)=Yayoi Armor Outfit (Custom Color) +弥生の額当て(色)=Yayoi's forehead rest (color) +弧1(キャラ)=Arc 1 (Character) +弧1(通常)=Arc 1 (General) +弧2(キャラ)=Arc 2 (Character) +弧2(通常)=Arc 2 (General) +弧3(キャラ)=Arc 3 (Character) +弧3(通常)=Arc 3 (General) +弱アクション=Tired Slap +弱ピストン=Slow Loop +弱ループ=Slow Loop +弱前待機=Tired Waiting +強アクション=Fast Slap +強さ=Intensity +強ピストン=Fast Loop +強ループ=Fast Loop +強制ループ=Force Looping +強前待機=Fast Waiting +強調1=Emphasis 1 +強調2=Emphasis 2 +弾=Bullet +弾(色)=Bullet (color) +形状上=Upper Lip Thickness +形状下=Lower Lip Thickness +形状口角=Corner Shape +彩度=Saturation +彫りの深さ1=Wrinkle Depth 1 +彫りの深さ2=Wrinkle Depth 2 +影=Shadowing +影とアウトライン=Shadows & Outlines +影なし=No Shadows +影の濃さ=Shadow Density +影の表現=Shadow Type +影の表示=Shadow display +影の表示を変更します=Change shadow display +彼女を呼び出しますか?=Call her? +待ち合わせ=Rendezvous +待機=Idle +待機1=Idle 1 +待機1=Wait 1 +待機10=Idle 10 +待機11=Idle 11 +待機12=Idle 12 +待機13=Idle 13 +待機14=Idle 14 +待機2=Idle 2 +待機2=Wait 2 +待機3=Idle 3 +待機4=Idle 4 +待機5=Idle 5 +待機6=Idle 6 +待機7=Idle 7 +待機8=Idle 8 +待機9=Idle 9 +律子=Ritsuko +律子Pスカート(色)=Ritsuko P skirt (color) +律子の声の高低を設定します=Set the pitch of the voice of Ritsuko +律子の部屋=Ritsuko's room +律子の部屋(夕)=Ritsuko's room (evening) +律子の部屋(夜:消灯)=Ritsuko's room (night: lights off) +律子の部屋(夜:点灯)=Ritsuko's room (night: lit) +律子の部屋(抵抗)=Ritsuko's room (resistance) +律子の部屋(昼)=Ritsuko's room (day) +律子の部屋(脱力)=Ritsuko's room (weakness) +律子の音量を設定します=Set the Rhythm volume +律子ぱっつん=Ritsuko Puttsun +律子パンプス(色)=Ritsuko pumps (color) +律子ブレザー(色)=Ritsuko blazer (color) +律子レースパンツ(色)=Ritsuko Lace Pants (color) +律子レースブラジャー(色)=Ritsuko Lace Bra (color) +律子ロング=Ritsuko Long +律子床(抵抗)=Riko Floor (resistance) +律子床(豹変)=Ritsuko (bed change) +律子座り(抵抗)=Ritsuko sitting (resistance) +律子座り(豹変)=Ritsuko sitting (leaping change) +律子立ち(抵抗)=Ritsuko Standing (resistance) +律子立ち(豹変)=Ritsuko Standing (Ranged) +律子紐リボン(色)=Ribbon string ribbon (color) +律子紐リボン(色)位置調整=Ribo string ribbon (color) position adjustment +後ろ髪=Back +後ろ髪と横髪も同じ色に合わせる=Apply to Side Hair & Hair +後ろ髪のアウトラインの色=Back Hair Outline Color +後ろ髪の基本の色=Back Hair Base Color +後ろ髪の根本の色=Back Hair Root Color +後ろ髪の毛先の色=Back Hair Tip Color +後ろ髪の種類=Back Hair Type +後ろ髪の装飾の色01=Back Hair Accessory 01 Color +後ろ髪の設定=Back Hair +後嫌がりループ=After Dislike Loop +後方右ディフレクタ=Rear Right Deflector +後方左ディフレクタ=Rear left Deflector +後背位=Doggy Style +後背位(抵抗)=Doggy position (resistance) +後背位(脱力)=Doggy position (weakness) +後背位(豹変)=Doggy position (change) +後背位アナル=Anal Doggystyle +後輩キャラ=Kouhai +後髪=Back hair +得点台=Scoreboard +徘徊者=The Prowler +御武弥生=Yayoi Mikutake +御武弥生セット=Mibu Yayoi Set +御辞儀=Bow +微笑=Happy +徳利=KC Tokkuri +心情=Mentality +必殺=Special P +必殺技=Special Skill +必殺攻撃技=Special Attack Skill +必殺防御技=Special Defense Skill +忍びマフラー(色)=Shinobu muffler (color) +怒1=Angry 1 +怒10=Angry 10 +怒2=Angry 2 +怒3=Angry 3 +怒4=Angry 4 +怒5=Angry 5 +怒6=Angry 6 +怒7=Angry 7 +怒8=Angry 8 +怒9=Angry 9 +怒り=Bad mood +怒り2=Angry 2 +怒り2L=Furious L +怒り2R=Furious R +怒りマークA&B=Anger Mark A & B +怒りマークA&B(色)=Anger Mark A & B +怒る=Angry +思い出=Memories +思案=Thinking +思案L=Thinking L +思案R=Thinking R +怠惰=Lazy +急須(花柄)=Teapot (Flower) +性別=Gender +性器オナニー(抵抗)=Genital masturbation (resistance) +性器オナニー(脱力)=Genital masturbation (weakness) +性器オナニー(豹変)=Genital masturbation (reversal) +性器処女=Vaginal virgin +性器道具=Vibrator +性器非処女=Vaginal Experienced +性感帯=Erogenous Zone +性格=Pers. +性格:=Personality: +性格を選択=Personality Selection +性欲旺盛=Horny +性癖=Habit +恋人=Lover +恋人と会話=Conversation With Lover +恋人繋ぎ騎乗位=Sweetheart Connecting +恐れ=Fear +恥ずかしがり=Embarrassed +恥ずかしがる=Shy +恥ずかしがる1=Embarrassed 1 +恥ずかしがる2=Embarrassed 2 +恥ずかしがる3=Embarrassed 3 +恥まんぐり=Shame Prying +恵理子=Eriko +悔しい=Frustration +悩む=Worried +悪い遊び=Bad Play +悪魔の尻尾=Devil's tail +悪魔の尻尾(色)=Devil's tail (color) +悪魔の羽右用(色)=Demon feather right (color) +悪魔の羽左用(色)=Devil's feather for left (color) +悪魔の翼右用=Right Demon Wing +悪魔の翼左用=Left Demon Wing +悪魔の角=Devil Horns +悪魔ワンピース=Demonic One-Piece +悪魔尻尾=Demon Tail +悪魔羽右=Demon Wing Right +悪魔羽左=Demon Wing Left +悪魔角(色)=Devil horn (color) +悲しい=Sad +悲恸之龙=Dragon Of Sorrow +情報切替え=Switch info +情報確認=Show Info +惩戒营标识=PAME Sign +惰円吹き出し1右=Ellipse 1 Right +惰円吹き出し1右(影あり)=Ellipse 1 Right (Shadowed) +惰円吹き出し1左(影あり)=Ellipse 1 Left (Shadowed) +惰円吹き出し2右=Ellipse 2 Right +惰円吹き出し2右(影あり)=Ellipse 2 Right (Shadowed) +惰円吹き出し2左=Ellipse 2 Left +惰円吹き出し2左(影あり)=Ellipse 2 Left (Shadowed) +意地っ張り=Stubborn +意識高いクール=Wannabe +愛=Love +愛撫=Caressing +愛撫(抵抗)=Caress (resistance) +愛撫(脱力)=Caress (weakness) +愛撫(豹変)=Caressing (leaning) +愛称=Nick. +愛称:=Nickname: +愛称を入力して下さい=Please Enter A Nickname +愛称を確認=Display nicknames +愛花=Manaka's Dress (RL) +感情=Emotions +慎重=Cautious +慣れ=Exp. +战旗=Banner +战马=Horse +戦闘不能ビジュアル=Defeat +戦闘攻撃機(格納)=Combat attack aircraft (stored) +戦闘攻撃機(着艦)=Combat attack aircraft (landing) +戦闘攻撃機(飛行)=Combat attack aircraft (flight) +戦闘攻撃機(駐機)=Combat attack aircraft (tarmac) +戸=Door +戻る=Back +所属=Affiliated +扇子=Folding Fan +扇子(閉)=Folding Fan (Closed) +扇子(開)=Folding Fan (Open) +扉1=Door 1 +手=Hand +手すり=Railings +手すり1=Handrail 1 +手すり2=Handrail 2 +手すり3=Handrail 3 +手すり4=Handrail 4 +手にぶっかけ=Bukkake on hand +手を当て笑う=Hand Laughing +手を振る=Waving +手を触れられ嫌がられる=Hating Hand Being Touched +手を触れられ恥ずかしがる=Embarrassed From Hand Touch +手形=Bill +手招き=Beckoning +手枷=Leather Handcuffs +手術台=Operating Table +手術器具置き=Surgical Instrument Table +手術用照明器=Surgical Illuminator +手袋=Gloves +手袋の種類=Glove Type +手袋の色01=Glove 01 Color +手袋の色02=Glove 02 Color +手袋の色03=Glove 03 Color +手袋の設定=Gloves Settings +手袋を初期の状態に戻す=Restore Default Glove Settings +手袋柄の色01=Glove Pattern 01 Color +手袋柄の色02=Glove Pattern 02 Color +手袋柄の色03=Glove Pattern 03 Color +手裏剣1=Shuriken 1 +手里剑=Shuriken +手錠=Handcuffs +手錠イメージ(鎖)=Handcuff (Chain) +手錠イメージ(閉)=Handcuff (Closed) +手錠イメージ(開)=Handcuff (Open) +手鏡=Hand Mirror +手雷1=Grenade 1 +手雷2=Grenade 2 +手雷3=Grenade 3 +打ち下ろし=Downhill +扳手=Wrench +技ビジュアル設定=Technique Setting +投げ01=Pitch 01 +投げ02=Pitch 02 +投光器アーム=Floodlight Arm +投光器ライト=Floodlight Light +投光器ロッド=Floodlight Rod +投擲=Kunai +投擲1=Throwing 1 +投擲2=Throwing 2 +投擲3=Throwing 3 +投稿数=Number of posts +投稿者=Author +折り畳み用机=Folding Desk +抜く=Extract +抱かれたい=Aroused +抵抗=Resistance +抹茶ラテ=Green Tea Latte +押し付けパイズリ=Pressed Paizuri +担架=Stretcher +拘束=Restraint +拘束バイブ=Captive Vibrator +拘束バンド右用=Right Restraint +拘束バンド左用=Left Restraint +拘束フェラ=Restraint Fellatio +拘束台(ハニー)=Restraint Board (Honey) +拘束台(ハニー)=Restraint Board (Honey) +拘束用首輪=Restraint collar +拘束紐=Restraint string +拘束鎖=Restraint Chain +招き猫=Lucky Cat +拡縮=Scale +拡縮X=X Scale +拡縮Y=Y Scale +拡縮Z=Z Scale +拡縮量=Scale Amount +拳銃=Handgun +拳銃1=Pistol 1 +拳銃2=Pistol 2 +拳銃3=Pistol 3 +拳闘士=Brawler +拷問器具=Torture Instrument Table +持ち看板=Handheld Sign +指先絆創膏右手=Right Hand Fingertip Bandage +指先絆創膏左手=Left Hand Fingertip Bandage +指定なし=Random +指差す=Pointing +指示されたい=Cooperative +指示棒=Guide Rod +振袖=Long-sleeved Kimono +挿入=Insert +挿入(抵抗)=Insertion (resistance) +挿入(脱力)=Insertion (weakness) +挿入(豹変)=Insertion (change) +挿入前待機=About To Insert +挿入待機=Inserted Loop +捂嘴的布=Cloth +捆绑椅子1=Chair 1 +捆绑椅子2=Chair 2 +捆绑椅子3=Chair 3 +捻恨=Torture +掃く=Sweeping +掛け合わす=Fuse +掛け軸1=Hanging Scroll 1 +掛け軸2=Hanging Scroll 2 +探すのをやめる=Exit Girl Finder +掲載物1=Notice 1 +掲載物2=Notice 2 +掲載物3=Notice 3 +掲載物4=Notice 4 +描画=Display +描画設定=Graphics +提灯=Paper Lantern +換気扇=Ventilation Fan +揺れ=Bouncing +揺れ制御=Shake Control +携帯A=Mobile Phone A +携帯A(色)=Mobile Phone A +携帯B=Mobile Phone B +携帯B(色)=Mobile Phone B +携帯電話=Mobile Phone +搾乳器・液入(2色)=Breast Pump · Liquid +搾乳器・空=Breast Pump · Empty +搾乳器・空(色)=Breast Pump · Empty +摺扇=[IIlus] Hand Fan +撕裂骨斧=Tear Bone Ax +撬棍=Crowbar +撮影=Take Picture +撮影して保存=Save +撮影して更新=Update the Image +撮影パネル=Save Character +撮影ブース=Photo Booth +撮影ブース(白)=Photography Booth (White) +撮影フレーム=Photography Frame +操作=Manual +操作ユニット=Active Unit +操作軸の設定=Axis Settings +操作軸を表示する=Show Control Axis +擬音テキストの表示=Display of onomatopoeic text +攻撃1=Attack 1 +攻撃2=Attack 2 +攻撃3=Attack 3 +攻撃4=Attack 4 +攻撃型原潜=Attack type submarine +攻撃技=Attack Skill +攻撃点=Attack P +放電=Electrical Discharge +敏捷=Agility +救护车01=Ambulance 01 +救护车02=Ambulance 02 +教卓=Teacher's Desk +教壇=Teacher's Podium +教室=Classroom +教室(夕)=Classroom (evening) +教室(夜:消灯)=Classroom (night: lights off) +教室(夜:点灯)=Classroom (night: lit) +教室(昼)=Classroom (day) +教室(脱力)=Classroom (weakness) +教室(豹変)=Classroom (reversal) +教室1-1=Classroom 1-1 +教室1-2=Classroom 1-2 +教室2-1=Classroom 2-1 +教室2-2=Classroom 2-2 +教室3-1=Classroom 3-1 +教室3-2=Classroom 3-2 +教室スピーカー=Classroom Speaker +教室机=Classroom Desk +教室椅子=Classroom Chair +教室用机=Classroom Desk +教室用椅子=Classroom Chair +教師=Teacher +数値を入力=Enter numeric value +数学教師=Math Teacher +敵ユニット=Enemy Unit +文字表示速度=Text Speed +文学少女=Bookish +料理するのは好き?=Likes To Cook? +斜ひし形(キャラ)=Parallelogram (Character) +斜ひし形(通常)=Parallelogram (General) +斜めストライプ=Slanted Stripes +斜めぱっつん(右)=Slanting Straight-Cut Bangs (Right) +斜めぱっつん(左)=Slanting Straight-Cut Bangs (Left) +斧=Ax +断头之镰=Broken Head Sickle +断面ウィンドウの表示を変更します=Change the display of section window +断面の表示=Display of section +断面図=Sectional View +断面表示=Section display +新しい順=New order +新しい順に並べる=Newest first +新スクール水着(紺)=New School Swimwear (Navy) +新スクール水着(赤)=New School Swimsuit (Red) +新たな獲物を探しに行く=Look for new prey +新規セーブ=New Save +新規保存=Save New +方天画戟=Long Spear 02 +方式=Method +旗=Flag +无影=CF AKW +无线跳蛋接收器=Wireless Receiver +无线跳蛋遥控器=Wireless Remote Control +既読=Read +日=Day +日付=Date +日常=Normal Day +日常セット=Normal Set +日常セットの服も変更する=Change Clothing +日常セットへコピー=Copy to Normal Set +日本三式轻战车=Japan Type 3 Light Tank +日本人形=Japanese Doll +日本刀=Katana +日本髪=Japanese hair +日焼け=Tan +日焼け跡=Suntan +日焼け跡の種類=Suntan Type +日焼け跡の色=Suntan Color +日焼け跡の設定=Tans +日用品=Daily Life +旧ダウンロード=Old Download +早=Fast +早期警戒機(始動)=Early warning aircraft (starting) +早期警戒機(格納)=Early warning aircraft (stored) +早期警戒機(着艦)=Early warning aircraft (landing) +早期警戒機(飛行)=Early warning aircraft (flight) +早期警戒機(駐機)=Early warning aircraft (tarmac) +明01=Ming 01 +明02=Ming 02 +明03=Ming 03 +明04=Ming 04 +明るい=Cheerful +明るい光の拡散を表現します=Express bright light diffusion +明るさ=Brightness +明子=Akiko +明子64分け(左)=Akiko 64 division (left) +明子Pミニスカート(色)=Akiko P miniskirt (color) +明子シャツベスト(色)=Akiko shirt vest (color) +明子スニーカー(色)=Akiko sneakers (color) +明子の声の高低を設定します=Set the pitch of Akiko's voice +明子の部屋=Akiko's room +明子の部屋(夕)=Akiko's room (evening) +明子の部屋(夜:消灯)=Akiko's room (night: lights off) +明子の部屋(夜:点灯)=Akiko's room (night: lit) +明子の部屋(昼)=Meiko's room (day) +明子の部屋(脱力)=Akiko's room (weakness) +明子の部屋(豹変)=Akiko's room (azari change) +明子の音量を設定します=Set Akiko's volume +明子ハイソックス(色)=Akiko High Socks (color) +明子ミディアム=Akiko Medium +明子床(抵抗)=Akiko Floor (resistance) +明子床(豹変)=Akiko Floor (Screen Change) +明子座り(抵抗)=Akiko sitting (resistance) +明子座り(豹変)=Akiko sitting (reversal) +明子立ち(抵抗)=Akiko Standing (resistance) +明子立ち(豹変)=Akiko Akira (Rabbit change) +明子縞パン(色)=Akiko striped bread (color) +明子縞ブラジャー(色)=Akiko stripe bra (color) +明度=Brightness +昏迷药水=Coma Potion +星=Star +星(前開き)=Star (Open Front) +星1=Star 1 +星1(キャラ)=Star 1 (Character) +星1(通常)=Star 1 (General) +星2=Star 2 +星2=Star 2 +星2(キャラ)=Star 2 (Character) +星2(通常)=Star 2 (General) +星3(キャラ)=Star 3 (Character) +星3(通常)=Star 3 (General) +星4(キャラ)=Star 4 (Character) +星4(通常)=Star 4 (General) +星A=Stars A +星A=Star A +星B=Stars B +星B=Star B +星のバレッタ=Star Barette +星のペンダント=Star Pendant +星の髪飾り=Star Ornament +昼=Noon +昼の町並み=Day Street +昼食に誘う=Invite to lunch +時計=Clock +時計1=Clock 1 +時計2=Clock 2 +時計3=Clock 3 +時計4=Clock 4 +時間(昇順)=Time(Ascending order) +時間(降順)=Time (Descending) +時間帯=Time zone +普通=Normal +普通(中)=Normal (medium) +普通(短)=Normal (short) +普通(長)=Normal (long) +普通フェード=Normal fade +暑がる=Hot +暗01=Dark 01 +暗02=Dark 02 +暗03=Dark 03 +暗04=Dark 04 +更新せず終了=Exit Without Updating +書類入れ=Document Holder +最中=Monaka​ +最前面=Frontmost +最大=Maximum +最大5件(名前順)=Maximum 5 (by name) +最大登校人数=Max. Students +最小=Minimum +最小化=Minimization +最終姉妹×広一=Final sisters × Koichi +最終雪子×主人公=Final Yukiko × Takeru +最終雪子×広一=Final Yukiko × Koichi +月=Monday +月桂樹のサークレット(色)=Laurel cirquelet (color) +有り=Present +有効にする=Enable +有紗=Yusa +服=Clothing +服カラーの一括管理=Bulk Clothing Color Change +服が非表示状態です=Clothes are hidden +服セット読込み=Load Clothing +服データの保存・削除=Save Clothing Set +服データの読込み=Load Clothing Set +服のコピー=Copy Clothing +服のみ=Clothes Only +服のみチェック=Clothes Only +服のみ読込み=Only Clothing +服の保存と削除=Save/Delete Clothing +服の柄①=Cloth Pattern ① +服の柄②=Cloth Pattern ② +服の柄③=Cloth Pattern ③ +服の状態=Clothing State +服の色①=Cloth Color ① +服の色②=Cloth Color ② +服の色③=Cloth Color ③ +服の設定=Clothes Settings +服の読み込み=Load An Outfit +服状態=Clothes +服装=Clothing +服装(トップス)=Clothing (Tops) +服装(ボトムス)=Clothes (bottoms) +服装(ワンピース)=Clothing (One piece) +服装をチェックします=Clothing +服装表示を変更=Change clothing display +服読込み=Load Clothing +朝の公園=Morning At The Park +朝の町並み=Morning Street +朝礼台=Morning Assembly Stand +朧=Dazzling +木=Tree +木々のざわめき=Leaves Rustling +木のテーブル=Wood Table +木の丸テーブル=Wood Round Table +木の机=Wooden Desk +木の椅子=Wooden Chair +木の箱=Wooden Box +木の長椅子=Wooden Bench +木刀=Wooden Sword +木制口枷=PAME Gag01 +木机=Wooden age +木材市松模様=Wood Checkered Pattern +木柱=Wood Pillar +木柱1=Wood Pillar 1 +木柱2=Wood Pillar 2 +木桶=Wooden Pail +木梨柚帆=Kurosan Yuzo +木椅子=Wooden Chair +木椅子1=Wooden chair 1 +木椅子2=Wooden chair 2 +木皿1=Wood Tray 1 +木皿2=Wood Tray 2 +木目テーブル=Grain Table +木箱=Wooden Crate +木製オブジェ=Wooden Object +木製コーナー=Wooden Cornerpost +木製トンボ=Wooden Dragonfly +木製バット=Wooden bat +木製壁=Wood Wall +木製床=Wooden Floor +木製拘束具=Pillory +木质枷锁1=PAME Yokewooden1 +木鼓槌=Instrument_05 +未:Fマネキン=Female Mannequin +未:G寝1=Girl Laying 1 +未:G寝2=Girl Laying 2 +未:G寝3=Girl Laying 3 +未:G寝4=Girl Laying 4 +未:G座り1=Girl Sitting 1 +未:G座り2=Girl Sitting 2 +未:G座り3=Girl Sitting 3 +未:G座り4=Girl Sitting 4 +未:Hポーズ1=H-Pose 1 +未:Hポーズ2=H-Pose 2 +未:Hポーズ3=H-Pose 3 +未:Hポーズ4=H-Pose 4 +未:Hポーズ5=H-Pose 5 +未:Mマネキン=Male Mannequin +未:M立ち1=Male Standing 1 +未:M立ち2=Male Standing 2 +未:M立ち3=Male Standing 3 +未:M立ち4=Male Standing 4 +未:M立ち5=Male Standing 5 +未:アンタってさー=You Are...? +未:いい度胸ね=Some Nerve, Huh? +未:その他=Active +未:むー=Grr— +未使用1左1=Unused 1 (Left 1) +未使用2右1=Unused 2 (Right 1) +未使用3閉じ1=Unused 3 (Closed 1) +未使用4左2=Unused 4 (Left 2) +未使用5右2=Unused 5 (Right 2) +未使用6閉じ2=Unused 6 (Closed 2) +未定=Undecided +未所属=Not affiliated +未設定=Not Set +末広がり=Suehiro +本1=Book 1 +本2=Book 2 +本3=Book 3 +本を探す=Searching For Book +本を見る=Looking At Book +本を読む1=Reading Book 1 +本を読む2=Reading Book 2 +本を読む待機1=About To Read Book 1 +本を読む待機2=About To Read Book 2 +本列=Row of Books +本当にアップロードしますか?=Really upload this? +本当に上書きしますか?=Really Overwrite This? +本当に削除しますか?=Really Delete This? +本当に戻しますか?=Do you want to go back? +本格焼酎鋸山(蓋つき)=Full-fledged Shochu Sawyama (With Lid) +本格焼酎鋸山(蓋なし)=Full-fledged Shochu Sawyama (Without Lid) +本棚=At Bookshelves +本立て=Bookend +札=Bill +札(色)=Tag (color) +札束(右)=Bundle (right) +札束(左)=Bundle (left) +机=Desks +机1=Desk 1 +机2=Desk 2 +机しゃがみ=Squatting On Desk +机で寝る=Sleeping At Desk +机によりかかる=Leaning On Desk +机に座る=Sitting On Desk +机バック=Doggystyle Against Desk +机バックアナル=Anal Doggystyle Against Desk +机バック愛撫=Caress (desk) +机を拭く=Wiping Desk +机上バック=Desk Back +机側位=Laying On Desk +机寝位=Laying On Desk +机座り=Sitting Om Desk +机後背位=Doggy Style on Desk +杏理=Anri +杖=Cane +杖1=Wand 1 +杖2=Misc Staff 2 +杜兰德尔之剑=Durandr's Sword +杜兰德尔之鞘=Durandr's Sheath +条件チェック解除=Uncheck condition +条件を全て外す=Reset Settings +東=East +東2=East 2 +松明=Torches +枪击=Shooting +枪击效果1=Shot Blast 1 +枪击效果10=Shot Blast 10 +枪击效果2=Shot Blast 2 +枪击效果3=Shot Blast 3 +枪击效果4=Shot Blast 4 +枪击效果5=Shot Blast 5 +枪击效果6=Shot Blast 6 +枪击效果7=Shot Blast 7 +枪击效果8=Shot Blast 8 +枪击效果9=Shot Blast 9 +架子鼓=Instrument_04 +柄=Pattern +柄①の大きさ(幅)=Pattern ① Width +柄①の大きさ(高さ)=Pattern ① Height +柄①の色=Pattern Color ① +柄②の大きさ(幅)=Pattern ② Width +柄②の大きさ(高さ)=Pattern ② Height +柄②の色=Pattern Color ② +柄③の大きさ(幅)=Pattern ③ Width +柄③の大きさ(高さ)=Pattern ③ Height +柄③の色=Pattern Color ③ +柄の種類=Pattern Type +柄の色=Pattern Color +柄の色1=Pattern Color 1 +柄の色2=Pattern Color 2 +柄の色3=Pattern Color 3 +柄パジャマピンク=Pattern Pajamas Pink +柄パジャマ青=Pattern Pajamas Blue +柄を選択して下さい=Please Select a Pattern +柄杓=Dipper +柊このみ=Hiiragi Konomi +柏木壮亮=Kashiwagi Sosuke +柏餅=Shokushi +柵=Fence +柵1=Rail 1 +柵2=Rail 2 +柵3=Rail 3 +柵4=Rail 4 +柵5=Rail 5 +标枪导弹=FGM-148 Javelin +校内床=School Floor +根本と毛先の色を個別に設定する=Enable Root And Tip Color Adjustment +格闘A=Fists A +格闘A1=Fighting A1 +格闘A2=Fighting A2 +格闘A3=Fighting A3 +格闘B=Fists B +格闘B1=Fighting B1 +格闘B2=Fighting B2 +格闘B3=Fighting B3 +格闘家=Martial Artist +格闘能力=Martial Arts Ability +桃花魁=Peach Courtesan +桃髪01=Peach hair 01 +桃髪02=Peach hair 02 +桃髪03=Peach hair 03 +案内板=Guide Plate +案内板1=Guide Plate 1 +案内板2=Guide Plate 2 +桐箪笥=Kiri Tansu +桔梗の紋(白)=Kikyou Crest (White) +桔梗の紋(黒)=Kikyou Crest (Black) +桜=Cherry Blossom +桜の花びら=Cherry Blossom Petals +桜餅=Sakura Rice +桟橋1=Pier 1 +桟橋2=Pier 2 +桟橋3=Pier 3 +棒・槍=Bo / Spear +棒・槍1=Polearm / Spear 1 +棒・槍2=Polearm / Spear 2 +棒・槍3=Polearm / Spear 3 +棒アイス=Bar Ice +棒球棒=Baseball Bat +棘ボール=Prickle Ball +棘吹き出し1右=Shocked 1 Right +棘吹き出し1右(影あり)=Shocked 1 Right (Shadowed) +棘吹き出し1左=Shocked 1 Left +棘吹き出し1左(影あり)=Shocked 1 Left (Shadowed) +棚=Shelves +棚1=Shelf 1 +棚2=Shelf 2 +棚3=Shelf 3 +棚4=Shelf 4 +棚5=Shelf 5 +棚6=Shelf 6 +棚7=Shelf 7 +棚8=Shelf 8 +椅子=Chair +椅子・机=Sitting At Desk +椅子1=Chair 1 +椅子1=Seated 1 +椅子2=Chair 2 +椅子2=Seated 2 +椅子3=Seated 3 +椅子オナニー=Masturbating In Chair +椅子クンニ=Chair Cunnilingus +椅子クンニA=Seated Cunnilingus A +椅子クンニB=Seated Cunnilingus B +椅子で寝る=Sleeping In Chair +椅子ノーハンドフェラ=Sitting No-Hand Blowjob +椅子ノーハンド先舐め=Seated No-Hand Tip Licking +椅子パイズリ=Seated Paizuri +椅子パイズリ+咥え=Seated Paizuri & Sucking +椅子パイズリ+舐め=Seated Paizuri & Licking +椅子パイズリ舐め=Sitting Licking Boobjob +椅子バック=Doggystyle Against Chair +椅子バックアナル=Anal Doggystyle Against Seat +椅子バック愛撫=Caress (chair) +椅子またがりフェラ=Sitting Blowjob +椅子両手コキ=Sitting Double Handjob +椅子両手フェラ=Seated Two-Hand Blowjob +椅子亀頭いじり=Seated Glans Rubbing +椅子先舐め+竿舐め=Seated Tip & Shaft Licking +椅子対面=Seated Facing +椅子座=Sitting - Chair +椅子座(抵抗)=Chair seat (resistance) +椅子座(脱力)=Chair seat (weakness) +椅子座(豹変)=Chair seat (reversal change) +椅子座り=Sitting In Chair +椅子座り愛撫=Caress (sitting) +椅子片手コキ=Seated One-Hand Handjob +椅子背面=Seated Spooning +椅子背面騎乗=Sitting Reverse Cowgirl +椅子腕はさみパイズリ=Seated Hand-Assisted Paizuri +椅子足コキ=Sitting Foot Job +植物=Plants +楕円吹き出し1左=Ellipse 1 Left +業務用冷蔵庫=Business Refrigerator +極ビキニ(色)=Polar bikini (color) +極ビキニ(色変え可能)=Very Small Bikini (Custom Color) +極マイクロワンピース(色)=Extra-fine one-piece (color) +極マイクロワンピース(色変え可能)=Very Micro Piece (Custom Color) +楽しい=Pleased +槌・鎌=Hammer / Scythe +槌・鎌1=Hammer / Sickle 1 +槌・鎌2=Hammer / Sickle 2 +槌・鎌3=Hammer / Sickle 3 +槍1=Spear 1 +標準=Standard +横=Horizontal +横スケール=H Scale +横はねカール(右)=Swept-Out Curl (R) +横はねカール(左)=Swept-Out Curl (L) +横一文字=Horizontal Line +横位置=Spacing +横分けぱっつん(右)=Parted Trimmed Bangs (R) +横分けぱっつん(左)=Parted Trimmed Bangs (L) +横分けぱっつん_(右)=Parted Trimmed Bangs (R) +横分けヘア(右)=Sideswept Parted (R) +横分けヘア(左)=Sideswept Parted (L) +横回転=Rotation +横幅=Lenght +横幅を合わせる=Width +横座り=Legs To Side +横流しヘア(右)=Sideswept (R) +横流しヘア(左)=Sideswept (L) +横移動=Hor. +横結び=Horizontal knot +横線=Horizontal Lines +横縞ぱん(色変え可能)=Striped String Panties (CC) +横縞紐(色変え可能)=Striped String Bra (CC) +横長=Broad +横髪=Side hair +横髪のアウトラインの色=Side Hair Outline Color +横髪の基本の色=Side Hair Base Color +横髪の根本の色=Side Hair Root Color +横髪の毛先の色=Side Hair Tip Color +横髪の種類=Side Hair Type +横髪の装飾の色01=Side Hair Accessory 01 Color +横髪の設定=Side Hair +樽=Barrel +橋=Bridge +機械娘=Mechanical Girl +機能=Active +機能拡張=Extras +櫻井野乃花=Sakurai Nonoka +欠け四角(キャラ)=Square With Curve (Character) +欠け四角(通常)=Square With Curve (General) +次のシーンまでスキップしますか?=Do you want to skip to the next scene? +次のテキスト表示時に音声を停止=Voice Stops Before Next Text +次へ=Next +次回からは表示しない=Do not display from next time +欲求不満=Perverted +正の字=Counter +正の字1=Positive character 1 +正の字2=Positive character 2 +正円吹き出し1右=Circular 1 Right +正円吹き出し1右(影あり)=Circular 1 Right (Shadowed) +正円吹き出し1左=Circular 1 Left +正円吹き出し1左(影あり)=Circular 1 Left (Shadowed) +正円吹き出し2右=Circular 2 Right +正円吹き出し2右(影あり)=Circular 2 Right (Shadowed) +正円吹き出し2左=Circular 2 Left +正円吹き出し2左(影あり)=Circular 2 Left (Shadowed) +正台形(キャラ)=Perfect Trapezoid (Character) +正台形(通常)=Perfect Trapezoid (General) +正常位=Missionary +正常位(抵抗)=Regular position (resistance) +正常位(脱力)=Normal position (weakness) +正常位(豹変)=Normal position (latent change) +正座=Sitting Seiza +正統派ヒロイン=Typical Schoolgirl +正面=Forwards +步枪实弹=Rifle Live Ammunition +步枪弹壳=Rifle Shells +步枪弹头=Rifle Warheads +武器=Weapons +歩き1=Walk 1 +歩き2=Walk 2 +歩き3=Walk 3 +歩き4=Walk 4 +歩き5=Walk 5 +歩く=Walking +歩く・走る=Walking & Running +歩く1=Walking 1 +歩く2=Walking 2 +歪な欲望=Distorted Desire +歪み三角柱(キャラ)=Bent Triangle (General) +歪み三角柱(通常)=Bent Triangle (General) +歪み台形(キャラ)=Squared Trapezoid (Character) +歪み台形(通常)=Squared Trapezoid (General) +歪み多角形(キャラ)=Bent Tube (Character) +歪み多角形(通常)=Bent Tube (General) +死亡之翼=Deathwing +母性的=Motherly +母鸡=Chicken +毒刺导弹=FIM-92 Stinger +毛玉=Furball +毛糸=Yarn +毛糸のハイニーソ(色)=Woolen honeyso (color) +毛糸のハイニーソ(色変え可能)=Wool Thigs (Custom Color) +氏名=Name +気さく=Friendly +気分はどうだ?=How are you feeling? +気力=Spiritual +気力で肉体能力を高めて戦闘を行う。=Able to enhance combat ability with the body's vital force +気合=Fired Up +気弾=Magic +気弾1=Energy Bullet 1 +気弾2=Energy Bullet 2 +気弾3=Energy Bullet 3 +水かき(色変え可能)=Peek (color change possible) +水しぶき=Splash +水仙=Daffodil +水周り=Bathroom +水差し=Pitcher +水晶の斧=Crystal ax +水晶の盾=Crystal shield +水泳キャップ=Swimming Cap +水泳ゴーグル=Swimming Goggles +水泳ゴーグル(白)=Swimming goggles (white) +水泳ゴーグル(黒)=Swimming goggles (black) +水泳ゴーグル1=Swimming goggles 1 +水泳ゴーグル2=Swimming goggles 2 +水泳部=Swimming Club +水流=Water Flowing +水流(激)=Water Flowing (Strong) +水滴=Water Droplet +水玉=Polka Dots +水着=Swim Suit +水着タイプ=Swimsuit +水着トップス=Swimwear tops +水着の設定=Swimsuit Settings +水着ハンガー=Swimsuit hanger +水着ボトムス=Swimsuit bottoms +水着上=Upper Swimsuit +水着下=Lower Swimsuit +水色髪01=Light blue hair 01 +水色髪02=Light blue hair 02 +水色髪03=Light blue hair 03 +水遊び1=Water Play 1 +水遊び2=Water Play 2 +水道=Washbasin +水鉄砲=Water Gun +水面(川)=River Surface +水面(海)=Ocean Surface +水音=Water sound +水風船(柄)=Water Balloon (Patterned) +水風船(無地)=Water Balloon (Plain) +氷室麗華=Himuro Reika +永恒之塔单手武器1=Aion One-Handed Weapon 1 +永恒之塔单手武器2=Aion One-Handed Weapon 2 +永恒之塔双手剑=Aion Two-Handed Sword +永恒之塔双手剑2=Aion Two-Handed Sword 2 +永恒之塔双手斧=Aion One-Handed Axe +永恒之塔弓=Eternal Tower Bow +永恒之塔法杖=The Rod of Eternity +永恒之塔法杖2=The Rod of Eternity 2 +永恒之塔盾=Eternal Tower Shield +永恒之塔盾2=Eternal Tower Shield 2 +汁(上半身前面)=Juice (Upper Body Front) +汁(上半身背面)=Juice (Upper Body Back) +汁(下半身前面)=Juice (Lower Body Front) +汁(下半身背面)=Juice (Lower Body Back) +汁(顔)=Juice (Face) +汁垂れ=Dripping Juices +汁物の表現=Fluid Type +求・アナル1=Request / Anal 1 +求・アナル2=Request / Anal 2 +求・アナル3=Request / Anal 3 +求・口1=Requested mouth 1 +求・口2=Requested mouth 2 +求・口3=Requested mouth 3 +求・性器1=Request / Genital 1 +求・性器2=Request / Genitals 2 +求・性器3=Request / Genitals 3 +汉剑=Black Sword +汉剑鞘=Chinese Horse Sheath +汎用=General purpose +汎用ロングスカート=Universal Long Skirt +汎用上着用中央フリル=General Wear Center Frills +汎用呼吸=Generic Breathing +汗=Sweat +污秽之镰=Filthy Sickle +汪星人=Shiba +汲み取り便所=Scoop Toilet +汲み取り便所ドア=Scoop Toilet Door +決定=Accept +泉崎香奈=Izumizaki Kana +泡(単体)=Foam (Spherical) +泡(口用)=Foam (For Mouth) +泡(水面)=Foam (Water Surface) +泡バスルーム(プレプレ)=Bubble Bathroom 1 +泡バスルーム(らぶギア)=Bubble Bathroom 2 +泡まみれ=Soap Suds +波=Wave +波の音=Wave sound +波動・円=Energy Wave (Circle) +波動・斬=Energy Wave (Arc) +波動・柱=Energy Wave (Pillar) +泣き=Crying +注射ガーターリング(右)=Injection Ring Garter (Right) +注射ガーターリング(左)=Injection Ring Garter (Left) +注射器=Syringe +注射器\(大\)=Syringe (Large) +注射器\(小\)=Syringe (Small) +注射器・入=Syringe · Liquid +注射器・入(色)=Syringe · Liquid +注射器・空=Syringe · Empty +注射器1=Syringe 1 +注射器2=Syringe 2 +注射器ガーターリング右(色)=Syringe garter ring right (color) +注射器ガーターリング左(色)=Syringe garter ring left (color) +注意看板=Caution Sign +注視点=Crosshair +注視点の表示=Show Crosshair +注視点位置=Crosshair Location +注視点表示=Display gazing point +洋室壁([\d]+)=Western-Style Wall +洋式便器=Western-Style Toilet Bowl +洋照明1=Western lighting 1 +洋照明2=Western lighting 2 +洋照明3=Western light 3 +洋風ベッド=Western-Style Bed +洗濯バサミ=Clothespin +洗濯ばさみ=Clothespin +洗濯バサミ(桃)=Clothespin (peach) +洗濯バサミ(青)=Clothespins (blue) +洗濯バサミ(黄)=Clothespins (yellow) +洗面器=Washbasin +洗面器1=Sink 1 +洗面器2=Sink 2 +洗面器3=Sink 3 +洗面器台=Washbowl Stand +洗面所=Bathroom +洗面所(夕)=Washroom (evening) +洗面所(夜:消灯)=Toilet (night: lights off) +洗面所(夜:点灯)=Washroom (night: lit) +洗面所(昼)=Washroom (day) +洗面所(脱力)=Washroom (weakness) +洗面所(豹変)=Toilet (leather change) +活発=Lively +流し台=Washstand +浅いくっきり影=Slight, Sharp Shadows +浅いなめらか影=Slight, Smooth Shadows +浜辺=Beach +浜辺(砂)=Beach (All Sand) +浴缸梯子=ANG Tizi +海盗弯刀=Pirate Cutlass +海盗弯刀鞘=Pirate Scabbard +海盗船=Pirate Ship +海賊バンダナ(色変え可能)=Pirate bandana (color change possible) +海賊ブーツ=Pirate boots +海賊帽子=Pirate hat +海賊衣装=Pirate costume +海賊衣装上=Pirate costume +海賊衣装下=Under the pirate costume +海賊靴=Pirate shoes +海面_差し込み光が正面=Sea Surface (Front Light) +海面_差し込み光が背面=Sea Surface (Back Light) +海面_差し込み光無=Sea Surface (No Insertion Light) +海面用_反射抑え板=Reflection plate for sea surface +消しゴム=Eraser +消極的=Passive +消波ブロック=Wave-Breaking Block +消火器=Fire Extinguisher +消費=Usage Cost +消防斧=Fire Axe +涎=Drool +涙=Tears +涙Lv=Tears Level +液だまりA(濃)=Reservoir A (Thick) +液だまりA(薄)=Liquid Reservoir A (thin) +液だまりB(濃)=Reservoir B (Thick) +液だまりB(薄)=Liquid Reservoir B (thin) +液体=Urine +液体(黄)=Liquid (Yellow) +液体A=Semen Drip +液体A=Liquid A +液体A\(白\)=Liquid A (White) +液体A\(赤\)=Liquid A (Red) +液体A\(黄\)=Liquid A (Yellow) +液体B=Semen Spurt +液体B=Liquid B +液体B\(白\)=Liquid B (White) +液体B\(赤\)=Liquid B (Red) +液体B\(黄\)=Liquid B (Yellow) +液体ドロリ・不透=Liquid Oozing · Opaque +液体ドロリ・濃(色)=Liquid Oozing · Thick +液体ドロリ・薄(色)=Liquid Oozing · Thin +液体ドロリ・透可=Liquid Oozing · Clear +液体ドロリ直・透可=Liquid Oozing Straight · Clear +液体垂れ改(色)=Liquid Dripping +液体垂れ改・透可=Liquid Dripping · Clear +液体汁=Liquid +液体潮吹き・不透=Squirt of Liquid · Opaque +液体潮吹き・濃(色)=Squirt of Liquid · Thick +液体潮吹き・薄(色)=Squirt of Liquid · Thin +液体潮吹き・透可=Squirt of Liquid · Clear +液体飛び改(色)=Liquid Spurt +液体飛び改・透可=Liquid Spurt · Clear +液垂れ(濃)=Dripping liquid (Thick) +液垂れ(白)=Dripping (White) +液垂れ(薄)=Liquid Dripping (thin) +液垂れ(透明)=Dripping (Transparent) +液垂れ(黄)=Dripping (Yellow) +液垂れA・平面(色)=Dripping A · Planar +液垂れB・平面(色)=Dripping B · Planar +液溜まり=Semen Puddle +液溜まり\(白\)=Liquid Pool (White) +液溜まり\(赤\)=Liquid Pool (Red) +液溜まり\(黄\)=Liquid Pool (Yellow) +液溜まりA(白)=Liquid Pool A (White) +液溜まりA(透明)=Liquid Pool A (Transparent) +液溜まりA(黄)=Liquid Pool A (Yellow) +液溜まりB(白)=Liquid Pool B (White) +液溜まりB(透明)=Liquid Pool B (Transparent) +液溜まりB(黄)=Liquid Pool B (Yellow) +液溜まり改(色)=Liquid Sump Mod +液溜まり改・透可=Liquid Sump Mod · Clear +液飛び(濃)=Liquid Flying (Thick) +液飛び(白)=Spurt (White) +液飛び(薄)=Liquid Flying (thin) +液飛び(透明)=Spurt (Transparent) +液飛び(黄)=Spurt (Yellow) +淫=Horny +淫乱=Horny +淫乱2=Lewd 2 +深いくっきり影=Deep, Sharp Shadows +深いなめらか影=Deep, Smooth Shadows +混浴浴場=Mixed bath house +混音器=Instrument_14 +添い寝1=Sleeping Together 1 +添い寝2=Sleeping Together 2 +添い寝3=Sleeping Together 3 +添い寝キス=Lying kiss +清掃用バケツ=Bucket for cleaning +渡り廊下=Passageway +渦=Vortex +温泉=Hot Spring +湯のみ(花柄)=Cold Water (Flower) +湯呑み=A Cup Of Tea +湯気01=Steam 01 +湾曲角=Curved angle +湾曲角(色)=Curved angle (color) +満月=Full Moon +準備体操=Gymnast Preparation +溶解粘液=Dissolved mucus +溶解粘液1=Dissolving Liquids 1 +溶解粘液2=Dissolving Liquids 2 +溶解粘液3=Dissolving Liquids 3 +溶解粘液4=Dissolving Liquids 4 +溶解粘液5=Dissolving Liquids 5 +溶解粘液A=Slime A +溶解粘液A(色)=Melted mucilage A (color) +溶解粘液B=Slime B +溶解粘液B(色)=Dissolved mucilage B (color) +溶解粘液C=Slime C +溶解粘液C(色)=Solubilized mucilage C (color) +溶解粘液D=Slime D +溶解粘液D(色)=Dissolved mucilage D (color) +溶解粘液E=Slime E +溶解粘液E(色)=Dissolved mucilage E (color) +溶解粘液F=Slime F +溶解粘液F(色)=Dissolved mucilage F (color) +溶解粘液G=Slime G +溶解粘液G(色)=Dissolved mucilage G (color) +溶解粘液H=Slime H +溶解粘液H(色)=Dissolved mucilage H (color) +溶解粘液セット=Dissolved Mucus Set +滝=Waterfall +漫画汗=Manga Sweat +漫画汗(色)=Manga Sweat +漫研=Manga Club +漫研部=Manga Club +漫研部チラシ=Manga Club Leaflet +潔癖症=Clean Freak +激しい愛撫を拒否しない?=Won't Refuse Groping? +濃=100 +濃い=Dark +濃い液体(中)=Female Ejaculate (Average) +濃い液体(弱)=Female Ejaculate (Weak) +濃い液体(強)=Female Ejaculate (Strong) +濃さ=Thickness +濃厚=Rich +濃度=Strength +濡れTシャツ=Wet T shirt +火=Fire +火の玉=Ball Of Fire +火枪1=Pirate Musket 1 +火枪2=Pirate Musket 2 +火枪3=Pirate Musket 3 +火炎=Flame +火炮=Artillery +火焰=Flame +火花エフェクト=Spark Effect +火麒麟=CF AK47 +灯篭=Lanterns +灵车=Hearse +灼熱の火球を召喚して敵にぶつける。=Summons a red hot fireball to blast an enemy. +炎1=Flame 1 +炎2=Flame 2 +炮弹=Artillery Shell +炮弹堆=Shell Pile +炮弹塞=Armed Fort +点滴スタンド=Drip Stand +烟雾=Smoke +烟雾手雷=Smoke Bomb +焚き火A=Cooking Pot (For Campfire) +焚き火B=Campfire +焚火=Bonfire +焚火(大)=Bonfire (Large) +無=None +無し=None +無効にする=Disable +無口=Quiet +無理やり続ける=Continue to force +無理矢理キス=Forced Kiss +無理矢理フェラ=Forced Blowjob +無理矢理手コキ=Forced Handjob +無表情=Expressionless +焦り=Impatient +焦点幅=Focus Distance +焼きいも(1本)=Sweet Potato +焼きいも(袋入)=Sweet Potato (Bagged) +焼きいもホイル巻=Baked Potato (Foil) +焼きおにぎりと皿=Grilled Onigiri (Dish) +焼きおにぎり食べかけ=Grilled Onigiri (Bite) +焼肉と割り箸=Yakiniku and Chopsticks +焼肉のたれ=Grilled Meat Sauce +焼鳥ねぎま串1本=Yakitori Negima (Skewer) +焼鳥ねぎま串皿=Yakitori Negima (Dish) +焼鳥皮串1本=Yakitori-Gawa (Skewer) +焼鳥皮串皿=Yakitori-Gawa (Dish) +煙=Smoke +煙2=Smoke 2 +煙管=Smoke pipe +煙草=Tobacco +照れ=Bashful +照明=Illumination +照明スイッチ=Light Switch +熱気による空気のゆがみで敵を幻惑する=Dazzles enemies with the distortions of heat haze. +燃烧瓶=Molotov Cocktail +爆弾=Bomb +爆炸=Blast +爆炸效果A=Explosive A +爆炸效果B=Explosive B +爪=Nails +爪(キャラ)=Claw 1 (Character) +爪(通常)=Claw 1 (General) +爪のツヤの強さ=Nail Gloss +爪の色=Nail Color +爪の設定=Fingernails +片手コキ=One-Hand Handjob +片手フェラ=One-Hand Blowjob +片手剣=One-Handed Sword +片手剣1=One-Handed Sword 1 +片手剣2=One-Handed Sword 2 +片手剣3=One-Handed Sword 3 +片目隠し(右)=Covering Eye (R) +片目隠し(左)=Covering Eye (L) +片足上げ壁バック=Leg Lifted Doggystyle Against Wall +片足上げ壁バックアナル=Leg Lifted Anal Doggystyle Against Wall +片足上げ抱え=Leg Tucked In Arm +牛=Buffalo +牛すじ串=Beef Straw Skewer +牛の角=Cow Horns +牛乳コーヒー=Coffee With Milk Box +牛柄ニーソックス=Cow Pattern Thighhighs +牛柄手袋=Cow Pattern Gloves +牡丹のかんざし=Peony Hairpin +牡丹のかんざし(色)=Peony Kanzashi (color) +牡丹の髪飾り=Tree Peony Ornament +牡丹帯長(色)=Peony length (color) +牡丹帯長柄あり(色)=Botan belt There is a long pattern (color) +牢屋壁=Jail Wall +物体の陰影を強調します=Emphasize shade of object +物理=Physical +特性=Traits +特技=Ability +特技効果=Skill Effect +特技名=Special Ability +特殊=Special +特殊1=Special 1 +特殊2=Special 2 +特殊3=Special 3 +特殊4=Special 4 +特殊5=Special 5 +特殊D=Special D +特殊E=Special E +特殊F=Special F +特殊G=Special G +特殊表現の強さ=Face Overlay Strength +特殊表現の種類=Face Overlay Type +特警车01=Special Police Car 01 +特警车02=Special Police Car 02 +犬の鳴き声=Dog Barking +状態=State +狐の面(白)=[PCM] Fox Face (White) +狐の面(黒)=[PCM] Fox face (Black) +狗肉=Dog Meat (Fallout) +独角兽=Unicorn +狸の置物=Tanuki Ornament +猪=Pig 1 +猫1=Cat 1 +猫2=Cat 2 +猫シッポ(色)=Cat shippo (color) +猫のおもちゃ=Toy Cat +猫口閉じ=Catlike +猫头鹰=Owl +猫尻尾=Cat Tail +猫柄(冬物)=Cat Pattern (Winter) +猫水着=Cat Lingerie +猫耳(右)=Cat Ear (Right) +猫耳(左)=Cat Ear (Left) +猫耳(色)=Cat ear (color) +獅子=Shishi +獣耳・カチューシャ=Bear-ear / headband +玄関(内)=Entrance (inside) +玄関(内)(夕)=Entrance (inside) (evening) +玄関(内)(夜:消灯)=Entrance (inside) (night: lights off) +玄関(内)(夜:点灯)=Entrance (inside) (night: lighting) +玄関(内)(昼)=Entrance (inside) (daytime) +玄関(内・抵抗)=Entrance (inner · resistance) +玄関(内・脱力)=Entrance (inside / weakness) +玄関(外)=Entrance (outside) +玄関(外)(夕)=Entrance (outside) (evening) +玄関(外)(夜:消灯)=Entrance (outside) (night: lights out) +玄関(外)(夜:点灯)=Entrance (outside) (night: lit) +玄関(外)(昼)=Entrance (outside) (noon) +玄関(外・抵抗)=Entrance (outside · resistance) +玄関(外・脱力)=Entrance (outside / weakness) +玉いじり=Tama-ijiri +玉子=Egg +玉舐め=Ball Licking +玉飾り=New Year Ornament +王八盒子=Wangbahezi +王冠=Crown +玫瑰蝴蝶套装=Rose Butterfly Set +环子枪=Brown Long Spear +玻璃吊椅无色=Glass Hanging Chair (Colorless) +玻璃吊椅白色=Glass Hanging Chair (White) +玻璃吊椅紫色=Glass Hanging Chair (Purple) +現在の色=Current Color +現在地=Location +球体=Orb +環境設定のすべて項目を初期化します=Initialize all items of environment setting +環境音=Environment +環境音の音量を設定します=Set the volume of environmental sound +環境音量=Environment +瓶\(緑\)=Bottle (Green) +瓶\(茶\)=Bottle (Tea) +瓶1=Bottle 1 +瓶2=Bottle 2 +甘いのは好き?=Likes Sweets? +生命之灾=Life Disaster +生垣1=Hedge 1 +生垣2=Hedge 2 +生真面目=Strict +生锈枷锁2=PAME Yokeiron2 +生锈镣铐1=PAME Cuff01 +生锈镣铐2=PAME Cuff02 +电子琴=Instrument_06 +男=Man +男2・バックフェラ=2 Man Doggy Fellatio +男2・フェラ=2 Man Fellatio +男2・胸股間弄り=2 Man Groping Footjob +男2・騎乗位バック=2 Man Double Penetration +男2Aバック=Spit Roast A (2M) +男2Aフェラ=Blowjob A (2M) +男2A愛撫=Caress A (2M) +男2A騎乗位=Cowgirl A (2M) +男2Bバック=Spit Roast B (2M) +男2Bフェラ=Blowjob B (2M) +男2B愛撫=Caress B (2M) +男2B騎乗位=Cowgirl B (2M) +男2バック=Spit Roast (2M) +男2フェラ=Blowjob (2M) +男2愛撫=Caress (2M) +男2騎乗位=Cowgirl (2M) +男H奉仕=Male Service +男H挿入=Male Insertion +男カットイン=Male: Cut-In +男キャラ=Boys +男キャラ選択=Boy Selection +男のサブアクセサリー表示=Show Male's Sub Accessories +男のシルエット表示時の色=Male silouette color +男のメインアクセサリー表示=Show Male's Main Accessories +男の体表示=Show Male's Body +男の単色=Male Color +男の単色化=Monochrome Male +男の服表示=Show Male's Clothing +男の表示=Man's indication +男の表示【一括】=Display of a man 【collective】 +男の靴表示=Show Male's Shoes +男ライフル=Male: Rifle +男両手剣=Male: Two-Handed Sword +男受けクンニ=Face Rubbing +男小太刀1=Male: Short Sword 1 +男小太刀2=Male: Short Sword 2 +男弓矢=Male: Bow And Arrow +男性ボイス=Male Voices +男性器の表示=Display of female genitalia +男性器の表示【一括】=Display of male genitalia 【collective】 +男性器の表示を変更します=I will change the display of male genitalia +男性用便器=Men's Toilet Bowl +男投擲=Male: Throwing +男拘束=Man restraint +男拘束(脱力)=Man restraint (weakness) +男拘束(豹変)=Male restraint (reversal) +男拳銃1=Male: Pistol 1 +男拳銃2=Male: Pistol 2 +男根=Penis +男根サイズ=Penis Size +男根のみ=Penis Only +男根以外表示=Show Body +男根根本=Penis +男根表示=Show Penis +男格闘A=Male: Fighting A +男格闘B=Male: Fighting B +男棒・槍=Male: Polearm / Spear +男槌・鎌=Male: Hammer / Sickle +男気弾=Male: Energy Bullet +男水を掛けられる=Boy: Splashed By Water +男水を掛ける=Boy: Splashing Water +男準備体操=Boy: Warm-Up Exercise +男片手剣=Male: One-Handed Sword +男目線カメラ=Male eye camera +男盾と剣=Male: Sword And Shield +男立ち1=Male Standing 1 +男立ち2=Male Standing 2 +男立ち3=Male Standing 3 +男立ち4=Male Standing 4 +男立ち5=Male Standing 5 +男表示=Male Display +男魔法本=Male: Grimoire +男魔法杖=Male: Magic Wand +画像=Background +画像スケーリング方法=Image Scale +画像一覧=Backgrounds +画像板=Image Board +画面クリックで閉じます=Click on the screen to close it +画面にノイズエフェクトを施します=Apply a noise effect to the screen +画面の色味調整=Scene Shade Adjustment +画面効果=Screen effect +画面淵のエフェクトを変更します=Change the screen effect +画面端を暗くします=Darken the edge of the screen +画面表示サイズを変更します=Change screen display size +画面設定①=Screen setting ① +画面設定②=Screen setting ② +番傘=Coarse Oilpaper Umbrella +番号00=Number 00 +番号01=Number 01 +番号02=Number 02 +番号03=Number 03 +畳=Tatami +畳1=Tatami Mat 1 +畳1=Tatami 1 +畳2=Tatami Mat 2 +畳2=Tatami 2 +畳3=Tatami Mat 3 +畳4=Tatami Mat 4 +畳5=Tatami Mat 5 +畳んだ眼鏡(色)=Folded glasses (color) +疑問L=Doubt L +疑問R=Doubt R +疲れやすい=Tired +疲れる=Tiring +疲れ知らず=Never Tired +痛がり=Pain +痩せ型=Thin +発光の強さ=Light Intensity +発光色=Light Color +発見=Discovery +登校人数=Students At School +登録リスト=Play List +白ナース=White Nurse +白ビキニ=White bikini +白帯胴着=White Belt Gi +白帯胴着(Tシャツ無し)=White Belt Gi (No T-shirt) +白木拵えの納刀=Sheathed Wooden Sword +白木拵えの鞘=Wooden Sword Sheath +白木拵え刀=Wooden Sword +白木拵え納刀=Sheathed Wooden Sword +白水着パーカー=White Swimsuit Parka +白目=Eye Whites +白目のグラデ種類=Sclera Type +白目の色=Eye Whites +白目の色①=Sclera Color ① +白目の色②=Sclera Color ② +白色窜天猴=Mini Helicopter +白虎=White Tiger +白衣=Rakugo +白衣・タンクトップ=White coat · tank top +白衣・タンクトップ(カラー)=Coat + Tank Top (CC) +白髪01=Gray hair 01 +白髪02=White hair 02 +白髪03=Gray hair 03 +的子=Slave +皮卡车01=Pickup Truck 01 +皮卡车02=Pickup Truck 02 +皮革绑手=PAME Cuff04 +皿=Dish +皿(おでん用)=Plates (For Oden) +皿を磨く=Dish Washing +盘龙=CF RPK +監視台=Judge's Chair +目=Eyebrows +目・口・手=Eyes/Mouth/Hand +目がハート=Heart Eyes +目と鼻筋=Eyes and nose ridge +目に炎=Fiery Eyes +目のパターン=Eye Pattern +目の上下=Eye Vertical Position +目の上下位置=Eye vertical position +目の前後=Eye Depth +目の最前面表示=Eyes Through Hair +目の横位置=Eye Spacing +目の横幅=Eye Width +目の縦幅=Eye Height +目の角度=Eye Rotation +目の角度Y軸=Eye Angle 2 +目の角度Z軸=Eye Angle 1 +目の設定=Eye Settings +目の調整=Eye Adjustments +目の開き=Eye Openness +目の開き具合=Eye Opening +目を髪より手前に表示=Irises Shows Through Hair +目上下=Eye Height +目元=Eyes +目元(右)=Eye (right) +目元(左)=Eye (left) +目元1=Eye 1 +目元2=Eye 2 +目元3=Eye 3 +目元4=Eye 4 +目前後=Eye Depth +目周りの影=Shadowed Eyes +目周り強調=Eye around emphasis +目尻の上下位置=Outer Eye Corner Height +目尻上下位置=Outer Corner Height +目尻左右位置=Outer Corner Distance +目横位置=Eye Spacing +目隠し=Blindfold +目頭の左右位置=Inner Eye Corner Height +目頭上下位置=Inner Corner Height +目頭左右位置=Inner Corner Distance +直突式電動ディルド=Electric Dildo Drill +直线(粉)=Straight Wire (Pink) +直线(黑)=Straight Wire (Black) +直角1(キャラ)=Right Angle 1 (Character) +直角1(通常)=Right Angle 1 (General) +直角2(キャラ)=Right Angle 2 (Character) +直角2(通常)=Right Angle 2 (General) +直角3(キャラ)=Right Angle 3 (Character) +直角3(通常)=Right Angle 3 (General) +直角形(キャラ)=Right Angle Triangle (Character) +直角形(通常)=Right Angle Triangle (General) +直钢棍=Straight Steel Bar +相手キャラ選択=Partner Selection +相良美弥子=Miyako Sagara +盾1=Shield 1 +盾2=Shield 2 +盾と剣=Shield and Sword +盾と剣1=Sword And Shield 1 +盾と剣2=Sword And Shield 2 +盾と剣3=Sword And Shield 3 +眉=Eyebrows +眉・目・口=Brows / Eyes / Mouth +眉のパターン=Eyebrow Pattern +眉の上下=Eyebrow Vertical Position +眉の内側形状=Inner Eyebrow Shape +眉の外側形状=Outer Eyebrow Shape +眉の最前面表示=Brows Through Hair +眉の横位置=Eyebrow Spacing +眉の種類=Eyebrow Type +眉の色=Eyebrow Color +眉の色を陰毛の色に合わせる=Copy Pubic Hair Color To Eyebrows +眉の色を髪と陰毛に反映する=Copy Eyebrow Color To Hair And Pubic Hair +眉の色を髪の色に合わせる=Copy Hair Color To Eyebrows +眉の角度=Eyebrow Angle +眉の調整=Eyebrow Adjustments +眉を髪より手前に表示=Eyebrows Show Through Hair +眉毛とアンダーヘアも同じ色に合わせる=Apply to Eyebrows & Pubic Hair +眉毛とヒゲも同じ色に合わせる=Apply to Eyebrows & Beard +眉毛の色に合わせる=Match Eyebrows +眉毛の設定=Eyebrows +眉毛上下=Eyebrow Height +眉毛内側形状=Inner Arching +眉毛外側形状=Outer Arching +眉毛横位置=Eyebrow Spacing +眉毛角度Z軸=Eyebrow Angle +看板=Signboard +真剣=Serious +真剣1=Serious 1 +真剣2=Serious 2 +真理子=Mariko +真理子ショート=Mariko Short +真理子の音量を設定します=Set the volume of Mariko +真理子の高低を設定します=Set high and low of Mariko +真理子床(抵抗)=Mariko floor (resistance) +真理子床(豹変)=Mariko floor (reed change) +真理子座り(抵抗)=Mariko sitting (resistance) +真理子座り(豹変)=Mariko sitting (reversal) +真理子立ち(抵抗)=Mariko standing (resistance) +真理子立ち(豹変)=Mariko standing (reversal) +真祖の血統=True Ancestor's Lineage +真紅の稲妻=Crimson Lightning +真面目=Diligent +眼帯右用=For the right eye zone +眼帯左用=For the left eye zone +眼球=Pupils +眼鏡=Eyewear +眼鏡カラー=Eyewear Color +着崩した制服A=Uniformed uniform A +着崩した制服A=School Uniform A +着崩した制服B=Uniformed uniform B +着崩した制服B=School Uniform B +着替え1=Changing 1 +着替え2=Changing 2 +着替え3=Changing 3 +着替え4=Changing 4 +着替え5=Changing 5 +着替え6=Changing 6 +着替え7=Changing 7 +着物=Kimono +着物(C)=Kimono (CC) +着物(RP)=Kimono (RP) (CC) +着物(柄あり)=Kimono (Patterned) +着物(桃)=Kimono (Peach) +着物(赤)=Kimono (Red) +着物(黒)=Kimono (Black) +着物たすき掛け=Tasuki Kimono +着物ミニ(帯色)=Kimono mini (band color) +着物ミニ(帯色変え可能)=Kimono Mini Band (Custom Color) +着物ミニ(色)=Kimono mini (color) +着物ミニ(色変え可能)=Kimono Mini (Custom Color) +着物ミニ水色(帯色)=Kimono mini aqua color (band color) +着物ミニ水色(帯色変え可能)=Kimono Mini Light Blue (Custom Color) +着物ミニ赤(帯色)=Kimono mini red (band color) +着物ミニ赤(帯色変え可能)=Kimono Mini Red (Custom Color) +着衣=Clothed +睡眠1=Sleep 1 +睡眠2=Sleep 2 +睡眠3=Sleep 3 +睡眠4=Sleep 4 +睫毛の設定=Eyelashes +瞬き=Blinking +瞬きをしない=Disable Blinking +瞳=Pupil +瞳にハート=Heart Pupils +瞳に星=Star Pupils +瞳のグラデサイズ=Eye Gradient Size +瞳のグラデ上下調整=Eye Gradient Vertical +瞳のグラデ合成方法=Eye Gradient Strength +瞳のグラデ種類=Eye Gradient Type +瞳のサイズ=Pupil Size +瞳の上下位置=Iris Vertical Position +瞳の上下調整=Pupil Position +瞳の左右位置=Iris Spacing +瞳の幅=Iris Width +瞳の横幅=Pupil Width +瞳の種類=Eye Type +瞳の縦幅=Pupil Height +瞳の色①=Eye Color ① +瞳の色②=Eye Color ② +瞳の設定方法=Eye To Edit +瞳の高さ=Iris Height +矢=Arrow +矢印1(キャラ)=Arrow 1 (Character) +矢印1(通常)=Arrow 1 (General) +矢印2(キャラ)=Arrow 2 (Character) +矢印2(通常)=Arrow 2 (General) +矢印3(キャラ)=Arrow 3 (Character) +矢印3(通常)=Arrow 3 (General) +矢吹遼子=Ryoko Yabuki +矢泽妮可限定小飞机=Pink Mini Helicopter +矢絣=Arrow Feathers +知り合い=Acquaintance +知力=Intelligence +短=- +短パンキャミソール=Short bread camisole +短剣1=Dagger 1 +短剣2=Dagger 2 +石壁1=Stone Wall 1 +石壁2=Stone Wall 2 +石壁3=Stone Wall 3 +石壁4=Stone Wall 4 +石床1=Stone Floor 1 +石床1=Stone Floor 1 +石床2=Stone Floor 2 +石床2=Stone Floor 2 +石張り床=Stone Flooring +石柱=Stone Pillar +石柱1=Stone Column 1 +石柱2=Stone Column 2 +石油ストーブ=Petroleum Stove +石畳1=Stone Paving 1 +石畳2=Stone Paving 2 +石階段1=Stone Stairs 1 +石階段2=Stone Stairs 2 +砂1=Sand 1 +砂2=Sand 2 +砂地1=Sand 1 +砂地2=Sand 2 +砂浜=Sandy Beach +砂漠と遺跡=Desert And Remains +破れストッキング(色)=Tear stockings (color) +破れストッキング(色変え可能)=Torn Pantyhose (Custom Color) +破房子=Dilapidated House +破片手雷=Frag Grenade +破瓜=Deflowered +硬化させた光の壁で攻撃を防ぐ=Blocks attacks with a wall of vulcanized light. +確認操作パネル=Control Panel +神出鬼没=Suddenly Appears +神卫军大盾=Shoguns Great Shield +禁止=Prohibited +私服=Casual Clothes +私服風=Plainclothes Style +秋千椅子1=Swing Chair 1 +秋千椅子2=Swing Chair 2 +秋千椅子3=Swing Chair 3 +秋名山顶=Akina Mountain Top +秘かに=Secretly +移動=Move +移動X=Move X +移動Y=Move Y +移動Z=Move Z +移動オブジェクト=Controls +移動オブジェクト表示タイプ=Show Controls +移動オブジェクト追加位置=New Object Position +移動式投光器=Mobile Floodlight +移動軸のリセット=Reset movement axis +移動速度=Moving speed +移動量=Movement Amount +種付けプレス=Mating Press +種類=Pattern +種類変更時に前回の色を引き継ぐ=Use Previous Color When Changing Accessory +積極的=Assertive +穴あきキューブ(キャラ)=Hollow Cube (Character) +穴あきキューブ(通常)=Hollow Cube (General) +穴あき三角(キャラ)=Hollow Triangle (Character) +穴あき三角(通常)=Hollow Triangle (General) +穴あき六角形(キャラ)=Hollow Hexagon (Character) +穴あき六角形(通常)=Hollow Hexagon (General) +穴あき楕円(キャラ)=Hollow Elipse (Character) +穴あき楕円(通常)=Hollow Elipse (General) +空=Skies +空き教室=Unused Classroom +空き缶=Empty canister +空き部室=Unused Clubroom +空席全ランダム=Fill Empty +空気/噴出=Air / Squirt +空気/噴出(色)=Air / Spurt +穿ち旋風=Whirlwind Drill +突き上げ立ちバック=Upthrust Behind +窓=Window +窓を拭く=Wiping Window +窜天猴=Sincerity +窜天猴带螺旋桨=Spiritual Spirit +窜天螺旋桨=Spiral Helix +立ち=Standing +立ち01=Pose 01 +立ち02=Pose 02 +立ち03=Pose 03 +立ち04=Pose 04 +立ち05=Pose 05 +立ち06=Pose 06 +立ち07=Pose 07 +立ち08=Pose 08 +立ち09=Pose 09 +立ち1=Basic 1 +立ち1=Standing 1 +立ち10=Basic 10 +立ち10=Pose 10 +立ち11=Basic 11 +立ち11=Pose 11 +立ち12=Basic 12 +立ち12=Pose 12 +立ち13=Basic 13 +立ち13=Pose 13 +立ち14=Basic 14 +立ち14=Pose 14 +立ち15=Basic 15 +立ち15=Pose 15 +立ち16=Basic 16 +立ち16=Pose 16 +立ち17=Basic 17 +立ち17=Pose 17 +立ち18=Basic 18 +立ち18=Pose 18 +立ち19=Basic 19 +立ち19=Pose 19 +立ち2=Basic 2 +立ち2=Standing 2 +立ち20=Basic 20 +立ち20=Pose 20 +立ち21=Basic 21 +立ち21=Pose 21 +立ち22=Basic 22 +立ち22=Pose 22 +立ち23=Basic 23 +立ち23=Pose 23 +立ち24=Basic 24 +立ち24=Pose 24 +立ち25=Basic 25 +立ち25=Pose 25 +立ち26=Basic 26 +立ち26=Pose 26 +立ち27=Basic 27 +立ち27=Pose 27 +立ち28=Basic 28 +立ち28=Pose 28 +立ち29=Basic 29 +立ち29=Pose 29 +立ち3=Basic 3 +立ち3=Standing 3 +立ち30=Basic 30 +立ち30=Pose 30 +立ち31=Basic 31 +立ち31=Pose 31 +立ち32=Basic 32 +立ち32=Pose 32 +立ち33=Basic 33 +立ち33=Pose 33 +立ち34=Pose 34 +立ち4=Basic 4 +立ち4=Standing 4 +立ち5=Basic 5 +立ち5=Standing 5 +立ち6=Basic 6 +立ち6=Standing 6 +立ち7=Basic 7 +立ち7=Standing 7 +立ち8=Basic 8 +立ち8=Standing 8 +立ち9=Basic 9 +立ち9=Standing 9 +立ちオナニー=Masturbating While Standing +立ちオナホ手コキ=Standing Onahole Handjob +立ちキス=Standing Kiss +立ちクンニ=Standing Cunnilingus +立ちノーハンドフェラ=Standing No-Hand Blowjob +立ちのノーハンドフェラ=Standing No-Hand Blowjob +立ちパイズリ=Boob Job - Standing +立ちパイズリ(豹変)=Standing Fucking (Change) +立ちパイズリ+咥え=Standing Paizuri & Sucking +立ちパイズリ舐め=Standing Licking Boobjob +立ちバイブ挿入=Standing Vibrator +立ちバック=Standing Behind +立ちポーズ=Standing Pose +立ちポーズ1=Standing Pose 1 +立ちポーズ10=Standing Pose 10 +立ちポーズ11=Standing Pose 11 +立ちポーズ12=Standing Pose 12 +立ちポーズ13=Standing Pose 13 +立ちポーズ14=Standing Pose 14 +立ちポーズ15=Standing Pose 15 +立ちポーズ16=Standing Pose 16 +立ちポーズ17=Standing Pose 17 +立ちポーズ18=Standing Pose 18 +立ちポーズ2=Standing Pose 2 +立ちポーズ3=Standing Pose 3 +立ちポーズ4=Standing Pose 4 +立ちポーズ5=Standing Pose 5 +立ちポーズ6=Standing Pose 6 +立ちポーズ7=Standing Pose 7 +立ちポーズ8=Standing Pose 8 +立ちポーズ9=Standing Pose 9 +立ち両手フェラ=Standing Two-Hand Blowjob +立ち亀頭いじり=Standing Glans Rubbing +立ち咥え=Blowjob - Standing +立ち咥え(抵抗)=Jamming (resistance) +立ち咥え(脱力)=Standing (weakness) +立ち咥え(豹変)=Standing (change) +立ち愛撫=Caress (stand) +立ち手コキ=Handjob - Standing +立ち手コキ(抵抗)=Standing handjob (resistance) +立ち手コキ(豹変)=Standing handjob (leaning) +立ち手コキ玉いじり=Standing Handjob & Ballrub +立ち拘束挿入=Stockade +立ち拘束挿入2=Stockade 2 +立ち松葉=Standing Pine +立ち片手コキ=Standing One-Hand Handjob +立ち片手フェラ=Standing One-Hand Blowjob +立ち玉舐め手コキ=Standing Handjob & Ball Licking +立ち腕はさみパイズリ=Standing Hand-Assisted Paizuri +立ち舐め=Licking - Standing +立ち舐め(豹変)=Standing lick +立ち話し=Talking +立ち足コキ=Standing Footjob +立て看板=Billboard +立位=Standing +立位(抵抗)=Standing position (resistance) +立体半円(キャラ)=Solid Hemisphere (Character) +立体半円(通常)=Solid Hemisphere (General) +立体四半円(キャラ)=Solid Quadrasphere (Character) +立体四半円(通常)=Solid Quadrasphere (General) +竜巻風神剣=Tornado Wind God Sword +競泳(白ピンク)=Competition Swimsuit (White & Pink) +競泳(白青黄)=Competition Swimsuit (White, Blue & Yellow) +競泳(白青黄)[透け]=Competition Swimsuit (White, Blue & Yellow) [Transparent] +競泳(紺水黒)=Competition Swimsuit (Navy Blue, Water & Black) +競泳(紺灰)=Competition Swimsuit (Navy Blue & Dark Blue) +競泳(赤)=Swimming (red) +競泳(青)=Swimming (blue) +競泳(青水白)=Competition Swimsuit (Blue, Water & White) +競泳(青紺灰)=Competition Swimsuit (Blue, Navy Blue & Orange) +競泳ハーフスパッツ(色)=Swimming half spats (color) +競泳ライン=Swimming line +競泳水着=Competition Swimsuit +竹=Bamboo +竹刀=Bamboo Sword +竹半分=Half Bamboo +竹台=Bamboo Tower +竹垣=Bamboo Fence +竹柵=Bamboo Fence +竹箒=Bamboo Broom +竹食器=Bamboo Tableware +竿こすり=Rod Scrubbing +笑顔=Smiling +笑顔両目閉じ=Happy, Closed +笠原なつめ=Nasugi Kasahara +第3と第4の目=Third and fourth eye +第三の目=Third Eye +筒(キャラ)=Dot 1 (Character) +筒(通常)=Dot 1 (General) +筒2(キャラ)=Sot 2 (Character) +筒2(通常)=Sot 2 (General) +筒ゴミ箱=Cylinder trash +筒ゴミ箱黒=Cylinder Trash (Black) +筒四分(キャラ)=Quarter Tube (Character) +筒四分(通常)=Quarter Tube (General) +筒照明1=Tubular lighting 1 +箒=A broom +箒で掃く=Sweep with a Broom +箒持ち待機=About To Sweep +箒持ち待機さぼり=Idling On Broom +箪笥=Chest Of Drawers +箭壶=Arrow Sheath +箭矢=Bamboo Arrow +箱(ブラシ)=Box (Brush) +箱(台有)=Box (Normal) +箱(台無)=Box (No Mid) +箱(回転式)=Box (Rotating Type) +箱(注入式)=Box (Injection Formula) +箱(直突式)=Box (Direct-Injection Type) +箸=Chopsticks +範囲=Range +範囲:周囲2=Area: Radius 2 +範囲:扇形2=Area : Spread 2 +範囲:扇形3=Area : Spread 3 +簡単カード作成=Easy Card Creation +簡易体型=Simple body type +簡易体型設定=Simple Settings +簡素なパイプベッド=Simple Pipe Bed +籠手1右=Glove 1 RIght +籠手1左=Glove 1 Left +籠手2右=Glove 2 Right +籠手2左=Glove 2 Left +米粒=Grains of Rice +粉雪=Powdery Snow +精=Semen +精液クリア=Clear sperm +精美浴缸=Beautiful Bathtub +精美藤椅=Fine Wicker Chair +約束あり=Promised +紅潮=Blushing +紅白浮き輪=Red and white floating rings +紅茶カップ1=Tea cup 1 +紅茶カップ2=Tea cup 2 +紅茶ポット=Tea pot +紅茶皿=Black tea dish +紅葉=Iroha +紅葉の木=Autumn Leaves Tree +紋章付き盾=Shield With A Crest +紐リボン=String Ribbon +紐結いシニヨン=String Concertion +純真無垢=Pure +紙コップ=Paper Cup +紙吹雪=Confetti +紙箱1=Paper Box 1 +紙箱2=Paper Box 2 +紙袋(チョコ)=Paper Bag (Chocolate) +紙袋(リボン)=Paper Bag (Ribbon) +紙袋(縞)=Paper Bag (Stripes) +紙袋(花)=Paper Bag (Flower) +素直クール=Humble +素股=Crotch Rubbing +素股(抵抗)=Barefoot (resistance) +素股(脱力)=Barefoot (weakness) +紫ステージ=[PCM] Purple Stage +紫髪01=Purple hair 01 +紫髪02=Purple hair 02 +紫髪03=Purple hair 03 +細い=Thin +細カーブ=Fine curve +細ツインテール=Thin Twintails +細め(中)=Thin (medium) +細め(短)=Short (short) +細め(長)=Short (long) +細め(長)02=Short (long) 02 +細リボン=Fine Ribbon +細リボンA=Fine Ribbon A +細リボンB=Fine Ribbon B +細ロング=Long thin +細縦長=Long And Narrow +終了=End +終了しない=Do Not Close +終了しますか=Quit the Game? +終演=Cast: +絆創膏=Bandage plaster +結びヘアバンド=Knotted Hairband +結びロング=Conclusion Long +結わえロング=Tied Long +絞り=Aperture +絡み合う蛇=Intertwining snakes +絨毯=Carpet +絵を描く=Drawing +絵を描く待機=About to Draw +絵画1=Painting 1 +絵画2=Painting 2 +絶頂=Climax +絶頂(ベース待機)=Cum (base wait) +絶頂(ベース待機)=Cum (base wait) +絶頂(大ビク)=Cum (big bike) +絶頂(小ビク1)=Cum (Small Bikes 1) +絶頂(小ビク2)=Cum (Small Bikes 2) +絶頂させて=Cautious +絶頂ループ=Climax Loop +絶頂事後=Climax End +絶頂前ピストン=Waiting for Climax +絶頂前ループ=Before Climax Loop +絶頂弱事後=After Mutual Weak Climax +絶頂強事後=After Mutual Strong Climax +絶頂時の"尿"演出="Urine" production at the peak +絶頂開始=About To Climax +綱手枷=Rope Handcuffs +綱輪=Tsunawa +綱輪1=Ring 1 +綱輪2=Ring 2 +網=Netting +網タイツ=Fishnet Tights +網タイツA(白)=Net tights A (white) +網タイツA(赤)=Net tights A (red) +網タイツA(黒)=Net tights A (black) +網タイツB(白)=Net tights B (white) +網タイツB(黒)=Net tights B (black) +網ティーバック(色)=Net tea bag (color) +網ティーバック(色変え可能)=T Web (Custom Color) +網ニーソックス=Netted Kneesocks +網ニーソックスA(赤)=Net thigh thigh A (red) +網ニーソックスA(黒)=Net thigh ths A (black) +網ニーソックスB(赤)=Net thigh ths B (red) +網ニーソックスB(黒)=Net thigh thighs B (black) +網ニーソックスC(黒)=Net thigh th / C (black) +網長タイツ(色)=Net length tights (color) +網長タイツ(色変え可能)=Fishnet Tights (Custom Color) +網長タイツ(赤)=Net length tights (red) +網長タイツ(黒)=Net length tights (black) +綺麗=Full +綺麗好き=Likes Cleanliness +総合=Total +緑=Green +緑色=Green +緑髪01=Green hair 01 +緑髪02=Green hair 02 +緑髪03=Green hair 03 +線ハイライト=Line Highlight +編み込み=Weaved +編集データ読み込み=Load/Save Data +編集中=Editing +編集前に戻す=Revert Edits +縞=Stripe +縞グリーン=Striped green +縞パン=Striped pan +縞ブルー=Stripe blue +縦=Vertical +縦スケール=V Scale +縦一文字=Vertical Line +縦回転=Position +縦巻きロール=Drill Rolls +縦幅=Height +縦幅をあわせる=Lenght +縦移動=Vert. +縦笛=Flute +縦線=Vertical Lines +縦長窓=[PCM] Vertical Window +縫合=Suture +縮尺=Scale +繰り返す=Repeat +纏いつく風刃=Swirling Wind Blade +绯红女皇=Crimson Queen +缶ビール=Can Of Beer +置物=Ornaments +羊の角=Sheep Horns +美白=Pale +羽=KC Hagoita Hane +羽の髪飾り右用=Right Hair Feather +羽の髪飾り左用=Left Hair Feather +羽子板=KC Hagoita +翼右=Wing Right +翼右用(色)=For wing right (color) +翼左=Wing Left +翼左用(色)=For wing left (color) +耳=Ears +耳サイズ=Ear Size +耳のサイズ=Ear Size +耳の上部形状=Ear Upper Shape +耳の下部形状=Ear Lower Shape +耳の角度Y軸=Ear Angle Y Axis +耳の角度Z軸=Ear Angle Z Axis +耳の調整=Ear Adjustments +耳上部形状=Upper Ear Shape +耳下部形状=Lower Ear Shape +耳着脱=Toggle ear +耳角度Y軸=Ear Angle +耳角度Z軸=Ear Rotation +聴診器=Stethoscope +職員トイレ(男)=Staff Bathroom (Males) +職員室=Staff Room +肉付きスライダー=Fleshed slider +肉壁=Meat wall +肉感=Strength +肉感の強さ=Strenght +肉感の種類=Skin Type +肉球=Pawprint +肌=Skin +肌のツヤ=Skin Shine +肌のツヤの強さ=Skin Gloss +肌の色=Skin Color +肌の色(赤み部分)=Skin Color (Redder Areas) +肌の設定=Skin +肌ラインを表示する=Display Skin Detail Lines +肌艶=Skin Shine +肘周りの奥=Elbow Thickness +肘周りの幅=Elbow Width +肚兜=Dudou 1 +肚兜2=Dudou 2 +肚兜3=Dudou 3 +肚兜4=Dudou 4 +肚兜5=Dudou 5 +肚兜6=Dudou 6 +肚兜7=Dudou 7 +肚兜8=Dudou 8 +肛=Anal +肛塞=Butt Plug +股割り器=Splits Device +股間=Crotch +股間いじり=Fingering +股間オナニー=Crotch Masturbation +股間が敏感=Sensitive Pussy +股間こすり=Riding Arm Standing +股間で絶頂したい=Cum inside +股間反応開始=Initial Crotch Touch +股間周り=Crotch +股間弄り=Crotch Fondling +股間弄り(抵抗)=Crotch fiddling (resistance) +股間弄り(脱力)=Fatal footing (weakness) +股間弄り(豹変)=Fatal crotch (bruise) +股間注視=Crotch gaze +股間舐め=Crotch Licking +股間舐め(抵抗)=Licking crotch (resistance) +股間舐め(脱力)=Licking crotch (weakness) +股間舐め(豹変)=Crotch licking (reversal change) +股間触り待機=About To Grope Crotch +肥=Hefei +肩=Shoulder +肩の奥=Shoulder Thickness +肩吊りワイシャツ=Shoulder-Hung Dress Shirt +肩幅=Shoulder Width +背もたれ無し椅子=Backless chair +背もたれ無し長椅子=Backless couch +背中=Back +背中・うなじ=Between Shoulder Blades +背中アザ=Back aza +背中にぶっかけ=Bukkake on back +背中中央=Mid Back +背中右=R. Back +背中左=L. Back +背景=Background +背景オブジェクト表示を変更します=Change background object display +背景タイプ=Background type +背景の描画設定=Background drawing setting +背景の種類=Background +背景の表示=Display background +背景を切り替え=Switch background +背景色=Background color +背負いカバン=Leather Backpack +背負いボストン=Boston Bag +背面フレーム=Background +背面フレームを表示=Show Background Frame +背面立位=Reverse Standing +背面立位(抵抗)=Back standing (resistance) +背面騎乗=Reverse Cowgirl +背面騎乗位=Reverse Cowgirl +背面騎乗位(抵抗)=Backward woman on top posture (resistance) +背面騎乗位(脱力)=Back woman on top posture (weakness) +背面騎乗位(豹変)=Backward woman on top posture +胡瓜=Cucumber +胴=Torso +胴の種類=Body Type +胴体上=Neck +胴体上の奥=Upper Torso Thickness +胴体上の幅=Upper Torso Width +胴体上奥=Chest Thickness +胴体上幅=Chest Width +胴体下=Under the trunk +胴体下の奥=Lower Torso Thickness +胴体下の幅=Lower Torso Width +胴体下奥=Waist Thickness +胴体下幅=Waist Width +胴体肩周り=Neck Thickness +胴体肩周りの奥=Shoulder Thickness +胴体肩周りの幅=Shoulder Width +胴体肩周り奥=Thorax Thickness +胴体肩周り幅=Thorax Width +胴周り=Waist +胴着下=Gi Trousers +胸=Breast +胸アザ=Chest aza +胸いじり=Breast Fondle +胸が敏感=Sensitive Breasts +胸サイズ=Size +胸にぶっかけ=Bukkake on chest +胸のサイズ=Breast Size +胸の上下位置=Breast Vertical Position +胸の上下角度=Breast Vertical Angle +胸の傷=Chest injury +胸の好み=Breast Size +胸の尖り=Breast Length +胸の左右位置=Breast Spacing +胸の左右開き=Breast Direction +胸の形状=Breast Roundness +胸の揺れ(ダンピング)=Breast firmness +胸の柔らかさ=Breast Softness +胸の重さ=Breast Weight +胸モミ正常位=Missionary Groping +胸モミ騎乗=Cowgirl Groping +胸を見られ恥ずかしがる=Hiding Chest From Embarrassment +胸を触られ隠す1=Covering Chest From Touch 1 +胸を触られ隠す2=Covering Chest From Touch 2 +胸を触られ隠す3=Covering Chest From Touch 3 +胸上=Throat +胸上下位置=Breast Height +胸上下角度=Breast Angle +胸上中央=Center of Neck +胸反応開始=Initial Breast Touch +胸周り=Chest +胸揉み=Massage Breasts +胸揉み(抵抗)=Puncture resistance (resistance) +胸揉み(脱力)=Puncture (weakness) +胸揉み(豹変)=Breast stomach (bruise) +胸操作=Chest Controls +胸注視=Chest gaze +胸触り待機=About To Grope Breasts +脅威=Threat +脚=Leg +脚全体=Legs +脚包帯=Leg bandage +脱ぐ上=Take off +脱ぐ下=Take off +脱力=Exhaustion +脱力アクション=Tired Slap +脱力中出し=Tired Creampie +脱力中出し事後=Tired After Creampie +脱力事後=Tired After Climax +脱力前待機=Tired Waiting +脱力同時絶頂=Tired Climax Together +脱力外出し=Tired Climax Outside +脱力外出し事後=Tired After Climax Outside +脱力女絶頂=Tired Girl Climax +脱力弱ピストン=Tired Slow +脱力弱ループ=Tired Slow Loop +脱力強ピストン=Tired Fast +脱力強ループ=Tired Fast Loop +脱力抜く=Tired Pull Out +脱力挿入=Tired Insert +脱力汁垂れ=Tired Dripping Liquid +脱力絶頂=Tired Climax +脱力絶頂事後=After Weakness Caught +脱力絶頂前ピストン=Tired Waiting for Climax +脱力絶頂前ループ=Tired Waiting for Climax +脱力胸揉み=Exhausted Breast Massage +脱衣=Undressed +腕=Arm +腕アザ=Arm Aza +腕はさみパイズリ=Hand-Assisted Paizuri +腕ベルト=Arm Belt +腕全体=Arms +腕包帯=Arm bandage +腕引っ張り後背位=Arm-Grab Doggystyle +腕引っ張り後背位アナル=Arm-Grab Anal Doggystyle +腕引っ張り机バック=Arm-Grab Doggystyle Against Desk +腕引っ張り机バックアナル=Arm-Grab Doggystyle Anal Against Desk +腕引っ張り椅子バック=Arm-Grab Doggystyle Against Seat +腕引っ張り椅子バックアナル=Arm-Grab Doggystyle Anal Against Seat +腕時計=Wristwatch +腕章「委員長」="Committee Chair" Armband +腕章「実習」="Training" Armband +腕章「風紀」="Public Morals" Armband +腕組=Fold Arms +腕輪(色)=Bracelet (color) +腰=Waist +腰上=Waist upper +腰上の奥=Waist Thickness +腰上の幅=Waist Width +腰上奥=Pelvis Thickness +腰上幅=Pelvis Width +腰下=Lower back +腰下の奥=Hip Thickness +腰下の幅=Hip Width +腰下奥=Hips Thickness +腰下幅=Hips Width +腰前=Front Waist +腰右=Right Hip +腰左=Left Hip +腰巻カーディガン=Wrapped Cardigan +腰後ろ=Back Waist +腰振り=Shaking Hips +腹=Belly +腹・股間=Midriff +腹部=Belly Thickness +膝下の奥=Knee Thickness +膝下の幅=Knee Width +膣=Vaginal +自主行動開始(ダメージ1)=Start Action (Damage 1) +自主行動開始(ダメージ2)=Start Action (Damage 2) +自主行動開始(通常)=Start Action (Normal) +自分=Myself +自分以外=Others +自動=Automatic +自動販売機1=Vending Machine 1 +自動販売機2=Vending Machine 2 +自動送り待ち時間=Auto Wait Delay +自動露光=Auto exposure +自動露光の基準となる明るさを設定します=Set the brightness which is the standard for automatic exposure +自宅(夜メニュー)=Home (Evening Menu) +自宅(朝メニュー)=Home (Morning Menu) +自室=Bedroom +自室ベッド=Personal Bed +自室棚1=Bedroom Shelf 1 +自室棚2=Bedroom Shelf 2 +自室棚3=Bedroom Shelf 3 +自室棚4=Bedroom Shelf 4 +自室棚5=Bedroom Shelf 5 +自撮り=Taking Selfie +自撮り待機=Preparing For Selfie +自販機1=Vending Machine 1 +自販機2=Vending Machine 2 +自軍ユニット=Friend Unit +自転車=Bicycle +興味がある=Interested +舌A・上げ=Tongue A · Raise +舌A・上げ→=Tongue A · Raise → +舌A・上げ←=Tongue A · Raise ← +舌A・上げ大=Tongue A · Raise More +舌A・垂れ=Tongue A · Droop +舌A・垂れ→=Tongue A · Droop → +舌A・垂れ←=Tongue A · Droop ← +舌A・垂れ大=Tongue A · Droop More +舌B・上げ=Tongue B · Raise +舌B・垂れ=Tongue B · Droop +舌ペロ=Playful +舌出し口開け=Tongue Out +舐め=Eating +航空母艦アンテナ=Aircraft carrier antenna +航空母艦本体=Aircraft Carrier Body +般若面=Waja side +艦艇の模型=War Fleet Model +色=Color +色コピー=Copy Color +色コピー補助機能=Color copy menu +色ペン=Colored Pen +色分けハイソックス=Colored Cuff High Socks +色合い=Hue +色味=Shade +色影=Colored Shadow +色相=Hue +色設定=Color setting +艶やか=Glamorous +花=Flower +花のかんざし(色)=Flower Penetration (Color) +花のかんざし桃色(色)=Flower Pen Pink color (color) +花のかんざし紫色(色)=Flower pudding purple (color) +花の髪飾り(揺れ)=Flower Ornament (Moves) +花右頬=Flower right cheek +花壇1=Flower Bed 1 +花壇1=Flowerbed 1 +花壇2=Flower Bed 2 +花壇2=Flowerbed 2 +花壇3=Flower Bed 3 +花壇3=Flowerbed 3 +花左右頬=Flower left and right cheek +花左頬=Flower left cheek +花柄=Flowers +花柄ワンピース(桃)=Flower pattern one piece (peach) +花柄ワンピース(紺)=Floral dress (navy) +花柄草履(緑)=Flower pattern sandals (green) +花柄草履(赤)=Flower pattern sandals (red) +花瓶(ピンク)=Vase (Pink) +花瓶(丸)=Vase (Circle) +花瓶(筒)=Vase (Tube) +花瓶(陶器)=Vase (Pottery) +花魁(桃)=Hana Kaori (peach) +花魁(黒)=Hana Kaoru (black) +花魁カンザシ=Flower Kanzashi +花魁カンザシ6本挿し=Flower Kanzashi 6 pcs +花魁クシ=Kanji Kana __ +花魁着物(桃)=Kaoru Kimono (peach) +花魁着物(黒)=Kaoru Kimono (black) +苦しい=Awkward +苦手=Reluctant +苦无=Kunai +英勇的亡者=The Heroic Dead +英国大游民坦克=British Tank +茂み=Thicket +茶畑=Tea Plantation (Map) +茶碗=Teacup +茶筅=Tea Whisk +茶道部=Tea Ceremony Club +茶髪01=Brown hair 01 +茶髪02=Brown hair 02 +茶髪03=Brown hair 03 +草原=Grass +草履=Zori +草履(色)=Sandals (color) +草履(色変え全体)=Sandals (Custom Color) +草履赤(色)=Sandals red (color) +草履赤(色変え可能)=Sandals Red (Custom Color) +草履黒(色)=Sandals black (color) +草履黒(色変え可能)=Sandals Black (Custom Color) +落ち込む=Depressed +落胆=Disappointed +葉っぱ=Leaves +葉月=Hazuki +葱タン塩(焼)=Salted Tongue with Welsh Onion +葱タン塩(生)=Salted Tongue with Welsh Onion (Raw) +葵=Aoi +蒼白=Pale +蒼白・縦線=Pale · Vertical Line +蔦輪=Iron Ring +薄=0 +薄い=Wispy +薄め=Dilute +薄眉=Light eyebrows +薄細=Thin thin +薄縦長=Long And Wispy +薔薇=Rose +薙ぎ払い=Mow Down +薪=Firewood +薪割り斧=Wood Split +薬莢=Pharmaceutical capsule +薬莢(色)=Capsule (color) +藤堂静香=Shizuka Todo +虎手袋=Tiger Gloves +虎水着=Tiger Swimsuit +虎靴=Tiger Shoes +虎靴下=Tiger Socks +虫かご(大)=Insect Cage (Large) +虫かご(小)=Insect Cage (Small) +虫の声=Crickets Chirping +虫の鳴き声=Insects +虫取りあみ=Bug-Catching Net +虹=Rainbow +蛇口1=Faucet 1 +蛇口2=Faucet 2 +蛍光灯=Fluorescent Lamp +蝋燭=Candle +蝶=Butterfly +蝶1=Butterfly 1 +蝶2=Butterfly 2 +蝶ネクタイ=Bow Tie +蝶ネクタイ(色)=Bow tie (color) +蝶の髪飾り=Butterfly Ornament +血液型=Blood Type +血液型:=Blood type: +血迹1=Blood 1 +血迹2=Blood 2 +血迹3=Blood 3 +血迹4=Blood 4 +血迹5=Blood 5 +血迹6=Blood 6 +血迹7=Blood 7 +血迹8=Blood 8 +血迹9=Blood 9 +行き倒れ1=Fallen 1 +行き倒れ2=Fallen 2 +行動=Action +行動追加(+1)威力上昇(+6)=Action(+1) Power(+6) +行李箱1=Trunk1 +行李箱2=Trunk2 +行李箱3=Trunk3 +術光輪=Art Ring of Light +術光輪(色)=Art Ring of Light +術剣=Artistic Sword +術剣(色)=Artistic sword +術盾=Art Light Shield +術盾(色)=Art Light Shield +街の鳥=Birds in the city +街灯=Street Light +街頭=Lamppost +衣装=Clothing +衣装上(着)=Costume on arrival +衣装下(着)=Under costume (arrival) +衣装切替=Switch +衣装読込=Clothing Set +表情=Facial expressions +表情(口)=Facial expression (mouth) +表情(目)=Facial expression (eye) +表情を変更=Change facial expression +表現方法=Light Settings +表示=Display +表示しない=Don't Display +表示する=Display +表示する靴のタイプ=Displayed Shoe Type +表示タイプ=Display Type +表示変更=Display change +表示選択=Select location +被写界深度=Depth of field +被写界深度の強さを調整します=Adjust the depth of field strength +被写界深度を有効にする=Enable Depth Of Field +装甲=Armor +装甲+7=Armor +7 +装甲狮鹫=Armored Golden Wanshi +装飾=Decoration +装飾の柄=Decoration Pattern +装飾の柄の大きさ(幅)=Decoration Pattern Width +装飾の柄の大きさ(高さ)=Decoration Pattern Height +装飾の柄の色=Decoration Pattern Color +装飾の種類=Decoration Type +装飾の色=Decoration Color +裏こすり=Rubbing Back +裏ボイスOFF=Back voice off +裏ボイスON=Back voice ON +裏庭=Rear Garden +裕子=Yuko +補助=Copy +補助1=Extra 1 +補助1=Auxiliary 1 +補助2=Extra 2 +補助2=Auxiliary 2 +補間値=Interp. +裸=Naked +裸エプロン=Naked apron +裸エプロン(ピンク)=Naked Apron (Pink) +裸エプロン(ピンク)=Naked apron (pink) +裸エプロン(白)=Naked apron (white) +裸サスペンダー=Naked Suspenders +裸サロペット=Naked Overalls +裸ワイシャツ=Naked shirt +複数H=Multiple H +襖1=Sliding Door 1 +襖2=Sliding Door 2 +襟の種類=Collar Type +西=West +西2=West 2 +西浦のどか分倍河原シホ=Nishiura throat Shimogawahara Seko +見つかった女の子=Found Girl +見学者ポーズ=Visitor pose +見本=Result +見開き本1=Opened Book 1 +見開き本2=Opened Book 2 +見開き本3=Opened Book 3 +見開き本4=Opened Book 4 +視力検査機=Eyesight Chart +視点=Point Of View +視線=Gaze +視線の向き=Gaze Direction +視線の向き調整=Eye Adjustment Tuning +覗き=Peep +親=Parent +親を初期設定に戻す=Reset To Default Parent +親を選択=Parent Selection +親変更=Position +観葉植物([\d]+)=Houseplant +観葉植物1=Decorative Plant 1 +観葉植物1=Houseplant 1 +観葉植物2=Decorative Plant 2 +観葉植物2=Houseplant 2 +観葉植物3=Decorative Plant 3 +観葉植物3=Houseplant 3 +観衆がいる場合の表示を切り替えます=Toggle display when there is an audience +観衆の表示=Display audience +観衆の音量を設定します=Set audience volume +角オナニー=Masturbating Against Corner +角なし三角(キャラ)=Beveled Triangle (Character) +角なし三角(通常)=Beveled Triangle (General) +角なし半四角錐(キャラ)=Beveled Half-Squared Pyramid (Character) +角なし半四角錐(通常)=Beveled Half-Squared Pyramid (General) +角なし四角(キャラ)=Beveled Square (Character) +角なし四角(通常)=Beveled Square (General) +角なし四角錐(キャラ)=Beveled Pyramid (Character) +角なし四角錐(通常)=Beveled Pyramid (General) +角なし斜ひし形(キャラ)=Beveled Parallelogram (Character) +角なし斜ひし形(通常)=Beveled Parallelogram (General) +角なし歪み台形(キャラ)=Beveled Squared Trapezoid (Character) +角なし歪み台形(通常)=Beveled Squared Trapezoid (General) +角リング(キャラ)=Angled Ring (Character) +角リング(通常)=Angled Ring (General) +角吹き出し1右=Angular 1 Right +角吹き出し1右(影あり)=Angular 1 Right (Shadowed) +角吹き出し1左=Angular 1 Left +角吹き出し1左(影あり)=Angular 1 Left (Shadowed) +角吹き出し2右=Angular 2 Right +角吹き出し2右(影あり)=Angular 2 Right (Shadowed) +角吹き出し2左=Angular 2 Left +角吹き出し2左(影あり)=Angular 2 Left (Shadowed) +角型(キャラ)=Angular Teardrop (Character) +角型(通常)=Angular Teardrop (General) +角度=Jaw Angle +角度Y軸=Angle +角度Z軸=Rotation +角皿(茶)=Square Tray (Brown) +角皿(黒)=Square Tray (Black) +触手=Tentacle +触手A・ヘッド1=Tentacle A · Head 1 +触手A・ヘッド2=Tentacle A · Head 2 +触手A・射精=Tentacle A · Ejaculation +触手A・巻き付き大=Tentacle A · Large Wrapping +触手A・巻き付き小=Tentacle A · Small Wrapping +触手A・通常=Tentacle A · Normal +触手A胴・カーブ1=Tentacle Body A · Curve 1 +触手A胴・カーブ2=Tentacle Body A · Curve 2 +触手A胴・カーブ3=Tentacle Body A · Curve 3 +触手A胴・ストレート=Tentacle Body A · Straight +触手A胴・太い=Tentacle Body A · Thick +触手B・ウネウネ=Tentacle B · Unaune +触手B・ぐるぐる=Tentacle B · Guruguru +触手B・ヘッド1=Tentacle B · Head 1 +触手B・ヘッド2=Tentacle B · Head 2 +触手B・射精=Tentacle B · Ejaculation +触手B・通常=Tentacle B · Normal +触手B胴・カーブ1=Tentacle Body B · Curve 1 +触手B胴・カーブ2=Tentacle Body B · Curve 2 +触手B胴・カーブ3=Tentacle Body B · Curve 3 +触手B胴・ストレート=Tentacle Body B · Straight +触手B胴・太い=Tentacle Body B · Thick +触手パーツ・イボ=Tentacle Parts · Wart +触手パーツ・吸盤=Tentacle Parts · Sucker +触手パンツ=Tentacle Pants +触手ブラ00=Tentacle Bra 00 +触手ブラ01=Tentacle Bra 01 +触手ブラ02=Tentacle Bra 02 +触覚(1本)=Ahoge (Single) +触覚(2本)=Ahoge (Twin) +触覚毛(色)=Haptic hair (color) +設定=Configuration +設定しているカメラ=Set Camera +設定を初期状態に戻す=Restore Defaults +設定初期化=Setting initialization +設置型松明=Installation Type Torch +設置物=Installed Objects +診察椅子=Examination chair +診察男受け=A Consultation +話し掛ける=Speak +話す=Talking +話す1=Talking 1 +話す10=Talking 10 +話す11=Talking 11 +話す12=Talking 12 +話す13=Talking 13 +話す14=Talking 14 +話す2=Talking 2 +話す3=Talking 3 +話す4=Talking 4 +話す5=Talking 5 +話す6=Talking 6 +話す7=Talking 7 +話す8=Talking 8 +話す9=Talking 9 +話づらい=Awkward +誕生日=Birthday +誕生日:=Birthday: +語学教師(担任)=Lang. Teacher (Homeroom) +誠実=Honest +読み込み=Load +読書好き=Likes Reading +読込み=Load +調整=Adjust +調整01=Adjustment 01 +調整02=Adjustment 02 +調整①をコピー=Copy Adjustment ① +調整①を上下反転コピー=Flip Adjustment ① Ver. On Copy +調整①を左右反転コピー=Flip Adjustment ① Hor. On Copy +調整②をコピー=Copy Adjustment ② +調整②を上下反転コピー=Flip Adjustment ② Ver. On Copy +調整②を左右反転コピー=Flip Adjustment ② Hor. On Copy +調整をコピー=Copy Adjustment +調整を上下反転コピー=Copy A. (Upside Down) +調整を左右反転コピー=Copy A. (Switch Left Right) +調整値=Adjustment +謝る=Apologize +警備ベルト=Security belt +警備員=Security guards +警備員タイト(紺)=Security guard tight (navy) +警備員タイト(黒)=Security guard tight (black) +警備員ネクタイ(紺)=Security guard tie (Navy) +警備員制服(紺)=Security guard uniform (dark blue) +警備員制服(黒)=Security guard uniform (black) +警棒=Batons +豚の着ぐるみ(色変え可能)=Pig costume (color change possible) +豚頭=Pig Head +豚頭(色)=Pig head (color) +豪華ソファ1=Expensive Sofa 1 +豪華ソファ1=Luxury sofa 1 +豪華ソファ2=Expensive Sofa 2 +豪華ソファ2=Luxury sofa 2 +豪龙胆=Haolongdan +豹のシッポ=Leopard's Shippo +豹変=Level change +豹変律子=Scolding change Ritsuko +豹変明子=Akagi changes Akiko +豹変雪子=Changes Yukiko +豹柄ファーリボン=Leopard fur ribbon +豹柄ワンピース=Leopard pattern one piece +豹耳=Pigeon ear +貝殻=Seashell +貝殻ビキニ(色)=Seashell bikini (color) +貝殻ビキニ(色変え可能)=Seashell Bikini (Custom Color) +財布(ホルダー)=Wallet +財布(本体)=Purse +貧乳=Petite +買物カゴ=Shopping Basket +資料棚=Material Shelf +質問=Nature +贝瑟尔之爪=Shaolin Claw +贞操带1=PAME Beltpadded +赤=Red +赤アロハ=Red Aloha +赤いハイビスカス=Red hibiscus +赤いベリーダンサー=Red Belly Dancer +赤と青=Red And Blue +赤バニー=Red Bunny +赤ボケ=Red Blur +赤み=Redness +赤色=Red +赤花柄浮き輪=Red flower pattern floating ring +赤面=Blush +赤髪01=Red hair 01 +赤髪02=Red hair 02 +赤髪03=Red hair 03 +走り=Running +走る1=Running 1 +走る2=Running 2 +走る3=Running 3 +走る4=Running 4 +起こして続ける=Keep up raising +足アザ=Foot Aza +足コキ=Foot Job +足コキ(抵抗)=Footjob (resistance) +足コキ(豹変)=Footjob (habit change) +足を組み待機1=Crosslegged 1 +足を組み待機2=Crosslegged 2 +足を組み換える1=Switching Legs 1 +足を組み換える2=Switching Legs 2 +足を組む=Cross Legs +足拭きマット=Foot wiping mat +足枷=Fettling +足袋=Tabi Socks +足袋(色)=Tabi (color) +足袋(色変え可能)=Tabi (Custom Color) +足首=Ankle +足首の奥=Ankle Thickness +足首の幅=Ankle Width +跳び箱=Vaulting Horse +跳び箱1=Vaulting Horse 1 +跳び箱2=Vaulting Horse 2 +跳び箱バック=Vaulting Horse Doggystyle +跳蛋(小)=Egg Vibrator (Small) +跳蛋(无线紫)=Egg Vibrator (Wireless Pink) +跳蛋(无线黑)=Egg Vibrator (Wireless Black) +跳蛋(粉)=Egg Vibrator (Pink) +跳蛋控制器(无线)=Controller (Wireless Black) +跳蛋控制器(白)=Controller (White) +跳蛋控制器(粉)=Controller (Pink) +踏み台1=Stool 1 +踏み台2=Stool 2 +踏切版=Starting Block +身長=Height +身長比較表=Height Comparison Board +身長計=Height Scale +車椅子=Wheelchair +軍服=Military Uniform +軍服タイトスカート=Military Tight Skirt +転入=Register +転校=Transfer +転校させますか?=Transfer to a different school? +軸の大きさ=Axis size +軸の表示=Display of axes +軸の速さ=Axis speed +軸の選択=Selection of axis +軽い=Lite +輪=Hoop +輪(キャラ)=Hoop (Character) +輪(通常)=Hoop (General) +輪郭=Contour +迷彩=Camouflage +迷彩窜天猴=Camo Mini Helicopter +追加01=Additional 01 +追加02=Additional 02 +追加1=Additional 1 +追加位置=Spawn Location +追加時の自動表示=Automatically Show +追加時の自動選択=Automatically Select +追尾=Tracking +逃げ足=Elude +逆さ押し車=Upside Down Thrust +逆らえない=Submissive +逆夜這い=Reverse Night Crawl +逆駅弁=Reverse Standing +逆駅弁(脱力)=Reverse station valve (weakness) +逆駅弁(豹変)=Reverse Evokeless Valve (Screen Change) +透明=Transparency +透明度=Alpha +通常=Normal +通常タイプ=Normal +通常待機=Normal Wait +通称=Title +速=Quick +速い=Fast +速度=Strenght +速度(移動量)=Speed (Movement Rate) +週間=Weekly +遅=Slow +運動しよう=Exercise +運動する?=Does Their Exercises? +運動好き=Likes Exercising +運動靴=Sneakers +道具(抵抗)=Tool (resistance) +道具(脱力)=Tool (weakness) +道具(豹変)=Tool (scratch) +遠くを見る=Looking Far Away +遥控器=Remote Control +遥控炸弹=Explosive +適応して終了=Adaptively close +適応しないで終了=Terminate without adaptation +適用しない=Cancel +適用する=Apply +遮光性アイマスク(色)=Light shielding eye mask (color) +遮断物の半透明化=Translucent of blocking material +遮断物設定=Shield setting +遮蔽物の自動非表示=Remove View Obstructions +遮蔽物を自動非表示=Hide obstructions automatically +選択=Select +選択した場所に移動しますか?=Move to the selected location? +選択画面=Selection screen +選択肢=Choice +選択肢後オート継続=Auto After Choices +選択肢後スキップ継続=Skip After Choices +選択表示=Selected +邪気眼=Delusional +部位:イヤリング右=Part: Right Earring +部位:イヤリング左=Part: Left Earring +部位:かかと右=Part: Right Heel +部位:かかと左=Part: Left Heel +部位:ツイン右=Part: Right Twintail +部位:ツイン左=Part: Left Twintail +部位:ヘアピン右=Part: Right Hairpin +部位:ヘアピン左=Part: Left Hairpin +部位:ポニー=Part: Ponytail +部位:口=Part: Mouth +部位:右ひざ=Part: Right Knee +部位:右ひじ=Part: Right Elbow +部位:右上腕=Part: Right Upper Arm +部位:右中指=Part: Right Middle Finger +部位:右乳首=Part: Right Nipple +部位:右人差指=Part: Right Index Finger +部位:右太もも=Part: Right Thigh +部位:右手=Part: Right Hand +部位:右手首=Part: Right Wrist +部位:右耳=Site: Right Ear +部位:右肩=Part: Right Shoulder +部位:右腕=Site: Right Arm +部位:右薬指=Part: Right Ring Finger +部位:右足=Site: Right Foot +部位:右足首=Part: Right Ankle +部位:女性器=Part: Female Genitalia +部位:尻穴=Part: Anus +部位:左ひざ=Part: Left Knee +部位:左ひじ=Part: Left Elbow +部位:左上腕=Part: Left Upper Arm +部位:左中指=Part: Left Middle Finger +部位:左乳首=Part: Left Nipple +部位:左人差指=Part: Left Index Finger +部位:左太もも=Part: Left Thigh +部位:左手=Part: Left Hand +部位:左手首=Part: Left Wrist +部位:左耳=Site: Left Ear +部位:左肩=Part: Left Shoulder +部位:左腕=Site: Left Arm +部位:左薬指=Part: Left Ring Finger +部位:左足=Site: Left Foot +部位:左足首=Part: Left Ankle +部位:帽子=Part: Hat +部位:男根根本=Part: Base Of Penis +部位:眼鏡=Part: Glasses +部位:背中中央=Part: Center Of Back +部位:背中右=Part: Right Of Back +部位:背中左=Part: Left Of Back +部位:胸=Site: Chest +部位:胸上=Part: Upper Chest +部位:胸上中央=Part: Center Of Upper Chest +部位:腰=Part: Waist +部位:腰前=Part: Front Of Waist +部位:腰右=Part: Right Waist +部位:腰左=Part: Left Waist +部位:腰後ろ=Part: Rear Of Waist +部位:頭=Site: Head +部位:頭上=Part: Top of Head +部位:頭中心=Part: Center of Head +部位:額=Part: Forehead +部位:首=Part: Neck +部位:鼻=Part: Nose +部員数=Club members +部室=Club Room +部屋=Room +部屋セット=Room Set +部屋セットへコピー=Copy to Room Set +部屋照明1=Room lighting 1 +部屋照明2=Room lighting 2 +部屋照明3=Room lighting 3 +部活=Club Activities +部活:=Club: +部活シャツ1A(カラー)=Camping Shirt 1A (CC) +部活シャツ1B(カラー)=Camping Shirt 1B (CC) +部活シャツ2A(カラー)=Camping Shirt 2A (CC) +部活シャツ2B(カラー)=Camping Shirt 2B (CC) +部活シャツ3A(カラー)=Camping Shirt 3A (CC) +部活シャツ3B(カラー)=Camping Shirt 3B (CC) +部活シューズ1A(カラー)=Sneakers 1A (CC) +部活シューズ1B(カラー)=Sneakers 1B (CC) +部活しよう=Do Koikatsu +部活スカート1A(カラー)=Club Activity Skirt 1A (CC) +部活スカート1B(カラー)=Club Activity Skirt 1B (CC) +部活と性格=Club/Pers. +部活パンツ1A(カラー)=Club Activity Panties (CC) +部活パンツ1A(カラー)=Club Activity Pants 1A (CC) +部活パンツ1B(カラー)=Club Activity Panties (CC) +部活パンツ1B(カラー)=Club Activity Pants 2B (CC) +部活パンツ2A(カラー)=Club Activity Pants 1A (CC) +部活パンツ2B(カラー)=Club Activity Pants 2B (CC) +部活ブラ1A(カラー)=Club Activity Bra 1A (CC) +部活ブラ1B(カラー)=Club Activity Bra 1B (CC) +部活水着1A(カラー)=Club activity swimwear 1A (CC) +部活水着1B(カラー)=Club activity swimwear 1B (CC) +部隊編成=Troop Formation +酒場=Bar +酒場前=Before the bar +酒場机=Tavern desk +酒場椅子=Bar Chair +酒樽=Barrel +酒甕=Sakagame +酔いエフェクトの表示=Show drunk effect +酔っ払い=Drunk +醤油ラーメン=Shoyu Ramen +醤油皿=Soy Sauce (Dish) +重鎧=Heavy Armor +野乃花=Nonoka +野原=Field +野性的=Wild +野次馬=Trainee +野点傘=Open Umbrella +野球バット=Baseball Bat +野球ヘルメット=Baseball Helmet +野球メット(赤)=Baseball Met (Red) +野球メット(黒)=Baseball Met (black) +野生的=Wild +金と碧のネックレス=Gold and blue necklace +金具つきビキニ(桃)=Bikini with bracket (peach) +金具つきビキニ(白)=Bikini with bracket (white) +金属ゴミ箱=Metal trash can +金属バット=Metal bat +金庫=Safe +金網フェンス=Chain-Link Fence +金髪01=Blond Hair 01 +金髪02=Blond Hair 02 +金髪03=Blond hair 03 +釜=Kettle +釣り=Fishing +釣り椅子=Fishing chair +釣り竿=Fishing rod +鈍感=Insensitive +鈴=Bell +鈴オーナメント=Bell Ornament +鈴付きチョーカー=Bell Choker +鈴付きリボン=Ribbon and Bell +鈴付き猫耳(色)=Cat with bells (color) +鈴音=Suzune +鉄の剣(色)=Iron sword (color) +鉄の剣の鞘(色)=Iron sword sheath (color) +鉄の矢=Iron Arrow +鉄の矢(色)=Iron arrow (color) +鉄十字の風神=Wind God of Iron Cross +鉄十字学園=Iron Cross Academy +鉄十字学園制服=Iron cross cruise school uniform +鉄十字学園制服セット=Iron Cross School Uniform Set +鉄格子の檻=Cage Of The Iron Grating +鉄骨=Steel Beams +鉛筆=Pencil +鉢巻=Headband +鉢巻(色)=Bow band (color) +鉤爪=Claw +銀獅式改変_紅蓮=Dragon Tooth Sword +銅鑼(ドラ)=Gong +錘=Weighted Shackle +錘(ハニー)=Weight (Honey) +錫杖1=Staff 1 +錫杖2=Staff 2 +錫杖3=Staff 3 +鍋つかみ(橙)=Pot hold (orange) +鍋つかみ(緑)=Pot hold (green) +鎌=Sickle +鎖=Chain +鎖1=Chain 1 +鎖2=Chain 2 +鎧ドレスA=Armor dress A +鎧ドレスB=Armor dress B +鎧ドレスガード右=Armor Dress Guard Right +鎧ドレスガード右(色)=Armor dress guard right (color) +鎧ドレスガード左=Armor Dress Guard Left +鎧ドレスガード左(色)=Armor dress guard left (color) +鎧ドレスグリーヴ(色)=Armor dress Greave (color) +鎧ドレスグローブ(色)=Armor dress gloves (color) +鎧ドレスショルダー右=Armor Dress Shoulder Right +鎧ドレスショルダー右(色)=Armor dress shoulder right (color) +鎧ドレスショルダー左=Armor Dress Shoulder Left +鎧ドレスショルダー左(色)=Armor dress shoulder left (color) +鎧ドレススカート(色)=Armor dress skirt (color) +鎧ドレスズボン(色)=Armor dress pants (color) +鎧ドレスセットA=Armor Dress Set A +鎧ドレスセットB=Armor Dress Set B +鎧ドレスヘッド(色)=Armor dress head (color) +鎧ドレスメイルA(色)=Armor dress Mail A (color) +鎧ドレスメイルB(色)=Armor dress Mail B (color) +鎧ドレスレギンス(色)=Armor dress leggings (color) +鎧兜=Armored Helmet +鎧兜(色)=Armor helmet (color) +鎧肩当て=Armored Shoulderpad +鎧肩当て右=Shoulder Armor Right +鎧肩当て右(色)=Shoulder to armor right (color) +鎧肩当て右用=Armored Shoulderpad (Right) +鎧肩当て左=Shoulder Armor Left +鎧肩当て左(色)=Armor against the shoulder left (color) +鎧肩当て左用=Armored Shoulderpad (Left) +鏡&カバー付ハンガーラック白=Mirror Clothes Rack (White) +鏡&カバー付ハンガーラック茶=Mirror Clothes Rack (Tea) +鏡_A=Mirror_A +鏡_B=Mirror_B +鏡_C=Mirror_C +鏡_D=Mirror_D +鏡_E=Mirror_E +鏡_F=Mirror_F +鏡の映り込み=Mirror reflection +鏡の表示=Mirror display +鏡の表示を変更します=Change the display of the mirror +鏡の配置=Mirror arrangement +钢环=Steel Ring +钢盾=Steel Shield +钢铁枷锁1=PAME Yokeiron1 +铁铲=Shovel +铁链(一圈)=Iron Chain (Looped) +铁链(弯)=Iron Chain +铁链(直)=Iron Chain (Straight) +铁锤=Hammer +铅弹=Lead Bombs +锈铁项圈1=PAME Collar01 +長=+ +長いす(おでん屋台用)=Long (For Oden Stand) +長ソファ=Long sofa +長テーブル低=Short Long Table +長テーブル高=Tall Long Table +長五角形(キャラ)=Long Pentagon (General) +長五角形(通常)=Long Pentagon (General) +長六角形(キャラ)=Long Hexagon (General) +長六角形(通常)=Long Hexagon (General) +長型カウチソファ=Long Form Couch +長手袋=Long Gloves +長方形=Rectangle +長柄大剣1=Nagareboshi Sword 1 +長柄斧1=Nagara Axe 1 +長柄斧2=Long Spear 2 +長椅子=Couch +長椅子1=Gym Bench 1 +長椅子2=Gym Bench 2 +長袖Tシャツ(紺)=Long-sleeved T-shirt (Navy) +長袖シャツベスト(色)=Long sleeve shirt vest (color) +長触覚=Long Ahoge +長靴=Boots +長靴(色変え可能)=Boots (color changeable) +长柄刀=Changdao Spear Sword +閉=Closed +閉じる=Close +開=Open +開き=Openness +開き紙=Open Paper +開始ポーズ=Start Pause +開始距離=Starting Distance +開発=Development +開脚正常位=Holding Legs Missionary +関係=Relationship +関節10=10° Joint +関節30=30° Joint +関節45=45° Joint +関節60=60° Joint +関節補正=Joint Adjustment +闇の鎧=Dark Armor +闪光手雷=Flash Bomb +防御=Blocking +防御技=Defense Skill +防御点=Defense P +防爆盾=Riot Shield +阿凯德纳的獠牙=Akadena's Fangs +阿帕奇=AH64a Heli +阿帕奇(飞行)=AH64b Heli +阿瓦隆=Avalon +陣羽織=Battle Surcoat +陥没乳首=Depressed nipple +陰毛=Pubic Hair +陰毛カラー=Pubic hair color +陰毛の種類=Pubic Hair Type +陰毛の色=Pubic Hair Color +陰毛の色を眉の色に合わせる=Copy Eyebrow Color To Pubic Hair +陰毛の色を髪と眉に反映する=Copy Pubic Hair Color To Hair And Eyebrows +陰毛の色を髪の色に合わせる=Copy Hair Color To Pubic Hair +陰陽=Yin-Yang +陶器1=Earthenware 1 +陶器2=Earthenware 2 +陶器小物1=Pottery accessories 1 +陶器小物2=Pottery accessories 2 +陶器小物3=Porcelain accessories 3 +陶器酒瓶=Pottery sake bottle +陸上部=Track & Field Club +階段=Stairs +階段(木)=Wooden Stairs +階段1=Staircase 1 +階段2=Staircase 2 +階段型(キャラ)=Stairs (Character) +階段型(通常)=Stairs (General) +階級バッジ=Rank Badge +障子=Shoji +障子1=Paper Door 1 +障子2=Paper Door 2 +隠す=Covering Self Up +隠すループ=Covering Self Up Loop +隷属=Slave +隷属2=Slave 2 +集中線=Focal Lines +集中線\(白\)=Intensive Line (White) +集中線\(黒\)=Intensive Line (Black) +集中線改・影無=Line Burst · No Shadow +雑巾=Dustcloth +雑誌=Magazine +雑貨=General Goods +雨=Rain +雨音=Rain +雪オーナメント=Snow Ornament +雪の結晶=Snow crystal +雪の結晶(ムフフ)=Snowflakes (Mufufu) +雪子=Yuko +雪子エプロンワンピース(色)=Yukiko apron one piece (color) +雪子サンダル(色)=Yukiko sandal (color) +雪子の声の高低を設定します=Set the pitch of Yukiko's voice +雪子の音量を設定します=Set the volume of Yukiko +雪子ローポニー(左)=Yukiko Ropony (left) +雪子床(抵抗)=Snow floor (resistance) +雪子床(豹変)=Yukiko (bed change) +雪子座り(抵抗)=Yukiko sitting (resistance) +雪子座り(豹変)=Yukiko sitting (reversal) +雪子立ち(抵抗)=Yukiko stand (resistance) +雪子立ち(豹変)=Yukiko standing (reversal) +雪子透けレースパンツ(色)=Yukiko transparent lace pants (color) +雪子透けレースブラジャー(色)=Yukiko transparent lace bra (color) +雪山の温泉=Snowy Mountain Hot Spring +雪駄(色)=Snow leaves (color) +雪駄(色変え可能)=Leather Soled Sandals (Custom Color) +雫=Drop Earring +雰囲気=Atmosphere +雲=Cloud +雲吹き出し1右=Cloud 1 Right +雲吹き出し1右(影あり)=Cloud 1 Right (Shadowed) +雲吹き出し1左=Cloud 1 Left +雲吹き出し1左(影あり)=Cloud 1 Left (Shadowed) +雲吹き出し2右=Cloud 2 Right +雲吹き出し2右(影あり)=Cloud 2 Right (Shadowed) +雲吹き出し2左=Cloud 2 Left +雲吹き出し2左(影あり)=Cloud 2 Left (Shadowed) +雷ハイライト=Lightning Bolt Highlight +雷吹き出し1右=Lightning 1 Right +雷吹き出し1右(影あり)=Lightning 1 Right (Shadowed) +雷吹き出し1左=Lightning 1 Left +雷吹き出し1左(影あり)=Lightning 1 Left (Shadowed) +雷吹き出し2右=Lightning 2 Right +雷吹き出し2右(影あり)=Lightning 2 Right (Shadowed) +雷吹き出し2左=Lightning 2 Left +雷吹き出し2左(影あり)=Lightning 2 Left (Shadowed) +雷神=CF M4L +雷穿=Lightning Pierce +電マを拒否しない?=Won't Refuse Vibrating Toys? +電化製品=Appliances +電子レンジ=Microwave Oven +電子回路=Electronic Circuit +電子回路(体)=Electronic circuit (body) 床 +電子回路(顔)=Electronic circuit (face) +電気スタンド1=Floor Lamp 1 +電気スタンド2=Floor Lamp 2 +電気スタンド3=Floor Lamp 3 +電気スタンド4=Floor Lamp 4 +電気スタンド5=Floor Lamp 5 +電気マッサージ器=Vibrating Wand +電気照明(和)1=Soft Electric Light 1 +電気照明(和)2=Soft Electric Light 2 +電気照明1=Electric Light 1 +電気照明2=Electric Light 2 +電気照明3=Electric Light 3 +電気照明4=Electric Light 4 +電気照明5=Electric Light 5 +電気照明6=Electric Light 6 +電波=Weirdo +電球=Light Bulb +電球(細)=Light Bulb (Cylinder) +電球照明=Bulb Light +電話のコール音=Telephone Ringing +電話台=Telephone Stand +電話台&ピッチラック茶=Telephone Pitch Rack (Tea) +電話台&ピッチラック黒=Telephone Pitch Rack (Black) +電車=Train +電車(脱力)=Train (weakness) +電車(豹変)=Train (reversal) +霜之哀伤=Frostmourne Sword +霧生茜=Mistress Akane +霰弹=Shotgun +露背毛衣@saw=Virgin-Killer Sweater @saw +青=Blue +青アロハ=Blue Aloha +青いハイビスカス=Blue hibiscus +青いベリーダンサー=Blue Belly Dancer +青い公園=Blue Park +青シャツ=Blue shirt +青チャイナドレス=Blue Cheongsam +青海波=Ocean Waves +青空=Blue Sky +青色=Blue +青花柄浮き輪=Blue flower pattern floating ring +青蔥=[IIlus] Blue +青蛙1=Frog 1 +青蛙2=Frog 2 +青髪01=Blue hair 01 +青髪02=Blue hair 02 +青髪03=Blue hair 03 +静滞之刃=Stagnant Blade +非常灯1=Emergency Light 1 +非常灯2=Emergency Light 2 +非常階段=Emergency Stairs +非表示=Hide Window +面包车1=Van 1 +面包车2=Van 2 +面包车3=Van 3 +面包车4=Van 4 +革カバン=Leather Bag +革カバン(色)=Leather bag (color) +革ソファ=Leather sofa +革ソファ茶=Leather Sofa (Tea) +革ソファ黒=Leather Sofa (Black) +革のサンダル(色)=Leather sandals (color) +革の手甲(色)=Leather handcraft (color) +革の首輪(茶)=Leather collar (tea) +革の首輪(黒)=Leather collar (black) +革椅子=Leather Chair +革椅子(高)=Leather chair (high) +革椅子1=Leather chair 1 +革鞄(褐)=Leather bag (brown) +革鞄(黒)=Leather bag (black) +靴=Shoes +靴(内履き)=Indoor Shoes +靴(外履き)=Outdoor Shoes +靴の種類=Shoe Type +靴の設定=Shoes Settings +靴下=Socks +靴下の種類=Legwear Types +靴下の色01=Legwear 01 Color +靴下の色02=Legwear 02 Color +靴下の色03=Legwear 03 Color +靴下の設定=Socks Settings +靴下を初期の状態に戻す=Restore Default Legwear Settings +靴下柄の色01=Legwear Pattern 01 Color +靴下柄の色02=Legwear Pattern 02 Color +靴下柄の色03=Legwear Pattern 03 Color +靴下着脱=Toggle socks +靴着脱=Toggle shoes +鞘=Katana Sheath +鞘小太刀=Sheathed Short Sword +鞘小太刀(色)=Sheath scallop (color) +鞭(ハニー)=Whip (Honey) +鞭(ハニー)=Whip (Honey) +鞭三角木馬(ハニー)=Whip Triangle Horse (Honey) +鞭三角木馬(ハニー)=Whip Triangular Wooden Horse (Honey) +音切丸=Sound notch +音切丸(色)=Sound notch (color) +音声=Voices +音声調整(低-高)=Voice Pitch (Low - High) +音楽を聴く=Listening To Music +音楽好き=Likes Music +音瑚=Sound +音瑚デフォ=Sound Default +音瑚役兎萌役=Mr. Sound Rabbit Robot +音量:システム音=Volume: System sound +音量:マスター=Volume: Master +音量:主人公=Volume: Hero character +音量:効果音=Volume: Sound effect +音量:広一=Volume: Hiroichi +音量:律子=Volume: Ritsuko +音量:明子=Volume: Akiko +音量:環境音=Volume: Environmental sound +音量:真理子=Volume: Mariko +音量:観衆=Volume: audience +音量:雪子=Volume: Yuko +音量:音声=Volume: Voice +音響効果=Sound effect +音響設定=Acoustic setting +頬=Cheeks +頬02=Cheek 02 +頬と鼻筋=Cheeks and nose ridge +頬のツヤの強さ=Cheek Gloss +頬の上下=Cheek Vertical Position +頬の丸み=Cheek roundness +頬の傷=Cheek wound +頬の前後=Cheek Depth +頬の幅=Cheek Width +頬の調整=Cheek Adjustments +頬を触られ嫌がられる=Hating Face Being Touched +頬上=On the cheek +頬上部上下=Upper Cheek Height +頬上部全体=Upper Cheek Overall +頬上部前後=Upper Cheek Depth +頬上部幅=Upper Cheek Width +頬下部上下=Lower Cheek Height +頬下部全体=Lower Cheek Overall +頬下部前後=Lower Cheek Depth +頬下部幅=Lower Cheek Width +頬側面上=On the buccal side +頬側面上02=On the buccal side 02 +頬側面下=Down the buccal aspect +頬赤=Face Flushing +頬赤の表示=Show Cheek Flushing +頬骨の前後=Cheekbone Depth +頬骨の幅=Cheekbone Width +頭=Head +頭(キャラ)=Head (Character) +頭(通常)=Head (General) +頭サイズ=Head Size +頭のサイズ=Head Size +頭の一部=Head Only +頭の大きさ=Head size +頭上=Forehead +頭中心=Center of Head +頻尿=Pees Often +額=Brow +額の傷=Scar of the forehead +額の目=Eye of forehead +額中央=Front center +額縁=Frame +顎=Jaw +顎の上下=Jaw Vertical Position +顎の下部上下=Lower Jaw Vertical Position +顎の下部奥行=Lower Jaw Depth +顎の先上下=Chin Tip +顎の先前後=Chin Depth +顎の先幅=Chin Width +顎の前後=Jaw Depth +顎の幅=Jaw Width +顎の調整=Jaw Adjustments +顎上下=Jaw Height +顎下部上下=Neck Droop +顎先の上下=Chin Vertical Position +顎先の前後=Chin Depth +顎先の幅=Chin Width +顎先上下=Chin Height +顎先前後=Chin Depth +顎先幅=Chin Width +顎前後=Jaw Depth +顎横幅=Jaw Width +顎角度=Jaw Angle +顔=Face +顔にぶっかけ=Bukkake on face +顔のタイプ=Facial Type +顔のプリセット=Facial Presets +顔の上部サイズ=Upper Face Size +顔の上部上下=Upper Face Height +顔の上部前後=Upper Face Depth +顔の下部前後=Lower Face Depth +顔の下部横幅=Lower Face Width +顔の全体横幅=Face Width +顔の簡易設定(全体)=Simplified Face Settings (Overall) +顔の簡易設定(口)=Simplified Face Settings (Mouth) +顔の簡易設定(目)=Simplified Face Settings (Eyes) +顔の簡易設定(眉)=Simplified Face Settings (Eyebrows) +顔の簡易設定(耳)=Simplified Face Settings (Ears) +顔の簡易設定(頬)=Simplified Face Settings (Cheeks) +顔の簡易設定(顎)=Simplified Face Settings (Jaw) +顔の簡易設定(鼻)=Simplified Face Settings (Nose) +顔の詳細設定(全体)=Advanced Face Settings (Overall) +顔の詳細設定(口)=Advanced Face Settings (Mouth) +顔の詳細設定(目)=Advanced Face Settings (Eyes) +顔の詳細設定(眉)=Advanced Face Settings (Eyebrows) +顔の詳細設定(耳)=Advanced Face Settings (Ears) +顔の詳細設定(頬)=Advanced Face Settings (Cheeks) +顔の詳細設定(顎)=Advanced Face Settings (Jaw) +顔の詳細設定(鼻)=Advanced Face Settings (Nose) +顔を見られ隠す=Hiding Face From View +顔上部上下=Face Height +顔上部前後=Upper Face Depth +顔下部前後=Lower Face Depth +顔下部横幅=Lower Face Width +顔全体の横幅=Face Width +顔全体の調整=Overall Facial Adjustments +顔全体横幅=Overall Face Breadth +顔包帯=Face Bandage +顔型の設定=Facial Settings +顔型をお手軽に設定=Enable Simple Face Settings +顔型全てデフォルト=Face Type Default +顔注視=Face gaze +顔面騎乗=Facesitting +顔面騎乗クンニ=Face Sitting Cunnilingus +風=Wind +風の力を秘めた魔剣。=A cursed sword containing the power of wind. +風呂=Bath +風呂(夕)=Bath (evening) +風呂(夜:消灯)=Bath (night: lights off) +風呂(夜:点灯)=Bath (night: lighting) +風呂(昼)=Bath (daytime) +風呂セット=Bath Set +風呂セットへコピー=Copy to Bath Set +風呂場カラン=Bathroom Curran +風呂場ボトル1=Bathroom bottle 1 +風呂場ボトル2=Bathroom Bottle 2 +風呂照明=Bath lighting +風神剣=Sword of the Wind God +风暴之矛=The Spear Of The Storm +飛び込み台1=Diving Board 1 +飛び込み台2=Diving Board 2 +飛び込み台3=Diving Board 3 +飛竜斬舞=Whirling Dragon Slash +飛龍型正規空母=Dragon Type Carrier +食べかけアイスバー=Half-Eaten Popsicle +食べる=Eating +食べるのは好き?=Likes To Eat? +食べ物=Food +食事A1=Eating A1 +食事A2=Eating A2 +食事A3=Eating A3 +食事B1=Eating B1 +食事B2=Eating B2 +食事C1=Eating C1 +食事C2=Eating C2 +食器棚=Cupboards +食堂=Cafeteria +食堂テーブル=Dining Table +食堂椅子1=Dining Chair 1 +食堂椅子2=Dining Chair 2 +食堂長テーブル=Long Dining Table +食材=Foodstuffs +飲ませる=Swallow +飲み物=Drinks +飲み込み=Swallowing +飲み込み待機=Swallowing wait +飲む=Drinking +飲む1=Drinking 1 +飲む2=Drinking 2 +飲む待機=About To Drink +飲んでね=Swallow it +養護教諭=School Nurse +首=Neck +首の向き=Head Direction +首の向き調整=Head Adjustment Tuning +首元クロス(白)=Head neck (white) +首元クロス(赤)=Crossed neck (red) +首元クロスTB(橙)=Neck cross TB (orange) +首元クロスTB(緑)=Necklace cross TB (green) +首周り=Neck Width +首周りの奥=Neck Thickness +首周りの幅=Neck Width +首周り奥=Neck Thickness +首周り幅=Neck Width +首手枷=Neck Handcuffs +首掛けメガホン=Hanging Megaphone +首操作=Head Operation +首枷=Metal Collar +首腕拘束帯=Kubiude Restraint Band +首輪=Collar +首輪(棘付)=Collar (With Thorns) +馬上槍1=Spear Horse 1 +馬上槍2=Spear Horse 2 +駅弁=Standing +駅弁(脱力)=Ekiben (weakness) +駅弁(豹変)=Ekiben (changeover) +駐輪場屋根=Bicycle Parking +騎乗位=Cowgirl +騎乗位(抵抗)=Woman on top posture (resistance) +騎乗位(脱力)=Woman on top posture (weakness) +騎乗位(豹変)=Woman on top posture +騎士=Knight +騎士のスーツ=Knight's Armor +騎士のスカート=Knight's Skirt +騎士のソックス=Knight's Socks +騎士のブーツ=Knight's Boots +騎士のレイピア=Knight's Rapier +騎士のレイピア(鞘)=Knight's Rapier (Sheath) +騎士の手袋=Knight's Gloves +騎士の肩当て=Knight's Shoulderpad +騎士の肩当て右用=Knight Shoulderpad (Right) +騎士の肩当て左用=Knight Shoulderpad (Left) +騎士の腰当=Knight's Hip Armor +騎士の腰当右用=Knight's Right Hip Armor +騎士の腰当左用=Knight's Left Hip Armor +騎士鎧=Knight armor +騎士鎧(色)=Knight armor (color) +騎士鎧(色変え可能)=Knight Armor (CC) +騎士鎧衣装セット=Knight Armor Costume Set +驚き=Surprised +驚きs=Surprised (Moderate) +驚恥他1=Surprise/Shame/Etc. 1 +驚恥他10=Surprise/Shame/Etc. 10 +驚恥他2=Surprise/Shame/Etc. 2 +驚恥他3=Surprise/Shame/Etc. 3 +驚恥他4=Surprise/Shame/Etc. 4 +驚恥他5=Surprise/Shame/Etc. 5 +驚恥他6=Surprise/Shame/Etc. 6 +驚恥他7=Surprise/Shame/Etc. 7 +驚恥他8=Surprise/Shame/Etc. 8 +驚恥他9=Surprise/Shame/Etc. 9 +骑士刺枪=Knight Spear +骑士标枪=Knight Javelin +骨付き肉=Meat with bone +骸骨=Skeleton +骸骨2=Skeleton 2 +骸骨面上顎=Skeleton surface maxilla +骸骨面上顎(色)=Skeleton surface upper jaw (color) +骸骨面下顎=Skeleton mandible +骸骨面下顎(色)=Skeletal mandible (color) +高=High +高い=Tall +高低:主人公=Pitch: Main character +高低:広一=Pitch: Hiroichi +高低:律子=Pitch: Ritsuko +高低:明子=Pitch: Akiko +高低:真理子=High and low: Mariko +高低:雪子=Pitch: Yukiko +高爆手雷=Illuminating Grenade +高飛車=Snobby +髪=Hair +髪のツヤ種類=Hair Highlight Type +髪の毛とアンダーヘアも同じ色に合わせる=Apply to Hair & Pubic Hair +髪の毛とヒゲも同じ色に合わせる=Apply to Hair & Beard +髪の毛と眉毛も同じ色に合わせる=Apply to Hair & Eyebrows +髪の毛の色に合わせる=Match Hair +髪の毛の色を統一する=Share Hair Colors +髪の色を眉と陰毛に反映する=Copy Hair Color To Eyebrows and Pubic Hair +髪の色を眉の色に合わせる=Copy Eyebrow Color To Hair Base +髪の色を陰毛の色に合わせる=Copy Pubic Hair Color To Hair Base +髪の設定=Hair +髪を直す=Fixing Hair +髪型=Hairstyles +髪留め=Barette +髪留め(色)=Hair clipper (color) +髪色=Hair color +髪色に連動=Interlocking with hair color +髪色を統一する=Share Hair color +髪飾り=Hair ornament +髪飾り(前)=Hair ornament(front) +髪飾り(後)=Hair ornament(back) +髪飾り(横)=Hair ornament(side) +髪飾りの色①=Hair Accessory Color ① +髪飾りの色②=Hair Accessory Color ② +髪飾りの色③=Hair Accessory Color ③ +髪飾りの色を初期に戻す=Set Accessory Color To Default +髪飾り色=Color 2 +髭=Beard +鬼神=Demon +鬼神のリボン=Demon God's Ribbon +鬼神の小手=Demon God's Gauntlets +鬼神の肩当て=Demon God's Shoulderpad +鬼神の脛当て=Demon God's Greaves +鬼神の腰当右用=Demon God's Hip Guard (Right) +鬼神の腰当左用=Demon God's Hip Guard (Left) +鬼神の装束(上)=Demon God's Costume (Top) +鬼神の装束A(下)=Demon God's Costume A (Bottom) +鬼神の装束B(下)=Demon God's Costume B (Bottom) +鬼神の金棒=Demon God's Iron Club +鬼神の額当て(右)=Demon God's Brow Guard (Right) +鬼神の額当て(右)=Demon God's Brow Guard (Right) +鬼神の額当て(左)=Demon God's Brow Guard (Left) +鬼神の額当て(左)=Demon God's Brow Guard (Left) +鬼越真紀=Maki Oniuchi +魅力的=Charmed +魔力=Magic +魔力使い=Mage +魔化之爪A=Magic Claws A +魔化之爪B=Magic Claws B +魔化之爪C=Magic Claws C +魔化之爪E=Magic Claws E +魔化剑刃戟A=Magic Halberd A +魔化剑刃戟B=Magic Halberd B +魔化剑刃戟C=Magic Halberd C +魔化剑刃戟D=Magic Halberd D +魔化剑刃戟E=Magic Halberd E +魔化战斧A=Magic War Ax A +魔化战斧B=Magic War Ax B +魔化战斧C=Magic War Ax C +魔化战斧D=Magic War Ax D +魔化战斧E=Enchanted Tomahawk E +魔化战斧F=Magic War Ax F +魔化战斧G=Magic War Ax G +魔化护手A=Magic Handguard A +魔化护手B=Magic Handguard B +魔化护手C=Enchanted Gauntlets C +魔化护手D=Magic Handguard D +魔化拳套A=Magic Fist A +魔化拳套B=Magic Fist B +魔化拳套C=Magic Fist C +魔化拳套D=Magic Fist D +魔化拳套E=Magic Fist E +魔化权杖A=Enchanted Scepter A +魔化权杖B=Enchanted Scepter B +魔化权杖C=Enchanted Scepter C +魔化权杖D=Enchanted Scepter D +魔化臂刃A=Magic Arm Edge A +魔化臂刃B=Magic Arm Edge B +魔化臂刃C=Magic Arm Edge C +魔化臂刃D=Magic Arm Edge D +魔化臂刃E=Magic Arm Edge E +魔化臂刃F=Magic Arm Edge F +魔化重锤A=Magic Hammer A +魔化重锤B=Magic Hammer B +魔化重锤C=Magic Hammer C +魔化重锤D=Magic Hammer D +魔化重锤E=Magic Hammer E +魔化重锤G=Magic Hammer G +魔化重锤H=Magic Hammer H +魔化重锤I=Magic Hammer I +魔化镰刀A=Magic Sickle A +魔化镰刀B=Magic Sickle B +魔化镰刀C=Magic Sickle C +魔化镰刀D=Magic Sickle D +魔化镰刀E=Magic Sickle E +魔化镰刀F=Magic Sickle F +魔化镰刀G=Magic Sickle G +魔化镰刀H=Magic Sickle H +魔化镰刀I=Magic Sickle I +魔化镰刀J=Enchanted Sickle +魔化镰刀K=Magic Sickle K +魔化阔剑A=Magic Broadsword A +魔女=Witch +魔女の帽子=Witch's hat +魔女の帽子(色)=Witch's hat (color) +魔女の手袋=Witch gloves +魔女の手袋L(カラー)=Witch Gloves L (CC) +魔女の手袋S(カラー)=Witch Gloves S (CC) +魔女の服=Witch clothing +魔女の服(カラー)=Witch Dress (CC) +魔女の靴=Witch's shoes +魔女の靴(カラー)=Witch Shoes (CC) +魔女風セット=Witch Style Set +魔導士セット=Magister Set +魔方陣=Magical Square +魔方陣2=Magic Square 2 +魔法のステッキ=Magical Wand +魔法のニーソックス=Magical Kneesocks +魔法のブーツ=Magical Boots +魔法の帽子=Magical Hat +魔法の書=Grimoire +魔法学園制服スカート=Magic Academy Uniform Skirt +魔法学園制服の袖=Magic Academy Uniform Sleeves +魔法学園制服上着=Magic Academy Uniform Top +魔法少女=Magical Girl +魔法本=Magic Book +魔法本1=Grimoire 1 +魔法本2=Grimoire 2 +魔法本3=Grimoire 3 +魔法杖=Magic Wand +魔法杖1=Magic Wand 1 +魔法杖2=Magic Wand 2 +魔法杖3=Magic Wand 3 +魔法陣=Magic Circle +魔火之舞=Magic Fire Dance +魔物タマ=Demon Testicles +魔物チン=Demon Penis +魔物チン(2色)=Demon Penis (2CC) +魔物チン・反り=Demon Penis · Erect +魔物チン・反り(2色)=Demon Penis · Erect (2CC) +魔物チン・萎え=Demon Penis · Flaccid +魔物チン・萎え(2色)=Demon Penis · Flaccid (2CC) +魔物舌・上げ=Demon Tongue · Raise +魔物舌・垂れ=Demon Tongue · Droop +魔鏡=Magic mirror +魔鏡(色)=Magic mirror (color) +魚肉ソーセージ=Fish Sausage +魚雷発射管の模型=Torpedo Tube Model +鮭とば=Salmon And Tomato +鮮やかさ=Saturation +鰻ざく=Eel +鳥のさえずり=Birds Chirping +鳥の仮面=Bird Mask +鳥の仮面(色)=Bird mask (color) +鷲掴み=Grasping +鷹=Falcon +鹅=Goose +鹿子=Deerskin +麗奈=Reina +麦わら帽子=Straw Hat +麦わら帽子(赤)=Straw Hat (Red) +麦わら帽子(青)=Straw hat (blue) +麦克风1=Instrument_01 +麦克风2=Instrument_02 +麦克风3=Instrument_03 +麻の葉=Hexagons +麻袋=Hemp Bag +黄アロハ=Huang Aloha +黄ボケ=Yellow Blur +黄桦弓=Yuan Bow +黄金麒麟=Golden Kirin +黑烟效果1=Black Smoke Effect 1 +黑烟效果2=Black Smoke Effect 2 +黑烟效果3=Black Smoke Effect 3 +黑烟效果4=Black Smoke Effect 4 +黑烟效果5=Black Smoke Effect 5 +黑烟效果6=Black Smoke Effect 6 +黑烟效果7=Black Smoke Effect 7 +黑皮眼罩=PAME Bilinder01 +黑色超渡=Black Salvation +黑铁铁链=PAME Legchain +黑铁镣铐1=PAME Cuff03 +黑铁镣铐带链子=PAME Cuff05 +黑龙王=Black Dragon King +黒ジャケットキャミソール=Black Jacket Camisole +黒バニー=Black Bunny +黒ビキニ=Black bikini +黒姫騎士=Kurohime Knight +黒帯胴着=Black Belt Gi +黒帯胴着(Tシャツ無し)=Black Belt Gi (No T-shirt) +黒帯胴着(袖無し)=Black Belt Gi (No Sleeves) +黒板=Blackboard +黒板(大)=Blackboard (large) +黒板(小)=Blackboard (small) +黒板\(大\)=Blackboard Large +黒板\(小\)=Blackboard Small +黒板消し=Blackboard Eraser +黒猫=Black Cat +黒花魁=Black Courtesan +黒電話=Black phone +黒髪=Black hair +鼻=Nose +鼻の上下=Nose Vertical Position +鼻の種類=Nose Type +鼻の調整=Nose Adjustments +鼻先サイズ=Tip Size +鼻先の高さ=Nose Tip Height +鼻先角度X軸=Tip Length +鼻先高さ=Tip Height +鼻全体上下=Nose Height +鼻全体前後=Nose Projection +鼻全体横幅=Nose Size +鼻全体角度X軸=Nose Angle +鼻筋の高さ=Nose Ridge Height +鼻筋形状=Bridge Shape +鼻筋横幅=Bridge Width +鼻筋高さ=Bridge Height +鼻筋高さと幅=Bridge Height & Width diff --git a/src/XUnity.AutoTranslator.Plugin.Core/UtageSupport/UtageHelpers.cs b/src/XUnity.AutoTranslator.Plugin.Core/UtageSupport/UtageHelpers.cs new file mode 100644 index 00000000..04e68130 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/UtageSupport/UtageHelpers.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace XUnity.AutoTranslator.Plugin.Core.UtageSupport +{ + public static class UtageHelpers + { + private static object AdvManager; + private static HashSet Labels = new HashSet(); + + public static void FixLabel( ref string label ) + { + var empty = new object[ 0 ]; + if( AdvManager == null ) + { + try + { + AdvManager = GameObject.FindObjectOfType( Constants.Types.AdvDataManager ); + var ScenarioDataTblProperty = Constants.Types.AdvDataManager.GetProperty( "ScenarioDataTbl" ); + var ScenarioDataTbl = ScenarioDataTblProperty.GetValue( AdvManager, empty ); + foreach( object labelToAdvScenarioDataKeyValuePair in (IEnumerable)ScenarioDataTbl ) + { + var labelToAdvScenarioDataKeyValuePairType = typeof( KeyValuePair<,> ) + .MakeGenericType( new Type[] { typeof( string ), Constants.Types.AdvScenarioData } ); + + var AdvScenarioDataKey = (string)labelToAdvScenarioDataKeyValuePairType.GetProperty( "Key" ) + .GetValue( labelToAdvScenarioDataKeyValuePair, empty ); + + Labels.Add( AdvScenarioDataKey ); + + var AdvScenarioData = labelToAdvScenarioDataKeyValuePairType.GetProperty( "Value" ) + .GetValue( labelToAdvScenarioDataKeyValuePair, empty ); + + if( AdvScenarioData != null ) + { + var ScenarioLabelsProperty = AdvScenarioData.GetType().GetProperty( "ScenarioLabels" ); + + var labelToAdvScenarioLabelData = ScenarioLabelsProperty.GetValue( AdvScenarioData, empty ); + + foreach( object labelToAdvScenarioLabelDataKeyValuePair in (IEnumerable)labelToAdvScenarioLabelData ) + { + var labelToAdvScenarioLabelDataKeyValuePairType = typeof( KeyValuePair<,> ) + .MakeGenericType( new Type[] { typeof( string ), Constants.Types.AdvScenarioLabelData } ); + + var AdvScenarioLabelDataKey = (string)labelToAdvScenarioLabelDataKeyValuePairType.GetProperty( "Key" ) + .GetValue( labelToAdvScenarioLabelDataKeyValuePair, empty ); + + Labels.Add( AdvScenarioLabelDataKey ); + } + } + } + } + catch( Exception e ) + { + Logger.Current.Warn( e, "An error occurred while setting up scenario set." ); + } + } + + if( !Labels.Contains( label ) ) + { + if( AutoTranslationPlugin.Current.TryGetReverseTranslation( label, out string key ) ) + { + label = key; + } + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Utilities/TextHelper.cs b/src/XUnity.AutoTranslator.Plugin.Core/Utilities/TextHelper.cs index 45e3cfc5..f68740c0 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Utilities/TextHelper.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Utilities/TextHelper.cs @@ -10,9 +10,28 @@ public static class TextHelper private static readonly Dictionary> LanguageSymbolChecks = new Dictionary>( StringComparer.OrdinalIgnoreCase ) { { "ja", ContainsJapaneseSymbols }, - { "ja-JP", ContainsJapaneseSymbols }, + { "ru", ContainsRussianSymbols }, + { "zh-CN", ContainsChineseSymbols }, + { "zh-TW", ContainsChineseSymbols }, + { "ko", ContainsKoreanSymbols }, + { "en", ContainsStandardLatinSymbols }, }; + private static readonly HashSet WhitespaceLanguages = new HashSet + { + "ru", "ko", "en" + }; + + public static bool IsFromLanguageSupported( string code ) + { + return LanguageSymbolChecks.ContainsKey( code ); + } + + public static bool RequiresWhitespaceUponLineMerging( string code ) + { + return WhitespaceLanguages.Contains( code ); + } + public static Func GetSymbolCheck( string language ) { if( LanguageSymbolChecks.TryGetValue( language, out Func check ) ) @@ -24,10 +43,75 @@ public static Func GetSymbolCheck( string language ) public static bool ContainsJapaneseSymbols( string text ) { - // Japenese regex: [\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf] + // Unicode Kanji Table: + // http://www.rikai.com/library/kanjitables/kanji_codes.unicode.shtml + foreach( var c in text ) + { + if( ( c >= '\u3021' && c <= '\u3029' ) // kana-like symbols + || ( c >= '\u3031' && c <= '\u3035' ) // kana-like symbols + || ( c >= '\u3041' && c <= '\u3096' ) // hiragana + || ( c >= '\u30a1' && c <= '\u30fa' ) // katakana + || ( c >= '\uff66' && c <= '\uff9d' ) // half-width katakana + || ( c >= '\u4e00' && c <= '\u9faf' ) // CJK unifed ideographs - Common and uncommon kanji + || ( c >= '\u3400' && c <= '\u4dbf' ) // CJK unified ideographs Extension A - Rare kanji ( 3400 - 4dbf) + || ( c >= '\uf900' && c <= '\ufaff' ) ) // CJK Compatibility Ideographs + { + return true; + } + } + return false; + } + + public static bool ContainsKoreanSymbols( string text ) + { + foreach( var c in text ) + { + if( ( c >= '\uac00' && c <= '\ud7af' ) ) // Hangul Syllables + { + return true; + } + } + return false; + } + + public static bool ContainsChineseSymbols( string text ) + { + foreach( var c in text ) + { + if( ( c >= '\u4e00' && c <= '\u9faf' ) + || ( c >= '\u3400' && c <= '\u4dbf' ) + || ( c >= '\uf900' && c <= '\ufaff' ) ) + { + return true; + } + } + return false; + } + + public static bool ContainsRussianSymbols( string text ) + { + foreach( var c in text ) + { + if( ( c >= '\u0400' && c <= '\u04ff' ) + || ( c >= '\u0500' && c <= '\u052f' ) + || ( c >= '\u2de0' && c <= '\u2dff' ) + || ( c >= '\ua640' && c <= '\ua69f' ) + || ( c >= '\u1c80' && c <= '\u1c88' ) + || ( c >= '\ufe2e' && c <= '\ufe2f' ) + || ( c == '\u1d2b' || c == '\u1d78' ) ) + { + return true; + } + } + return false; + } + + public static bool ContainsStandardLatinSymbols( string text ) + { foreach( var c in text ) { - if( ( c >= '\u3040' && c <= '\u30ff' ) || ( c >= '\uff00' && c <= '\uff9f' ) || ( c >= '\u4e00' && c <= '\u9faf' ) || ( c >= '\u3400' && c <= '\u4dbf' ) ) + if( ( c >= '\u0041' && c <= '\u005a' ) + || ( c >= '\u0061' && c <= '\u007a' ) ) { return true; } @@ -42,10 +126,9 @@ public static bool ContainsJapaneseSymbols( string text ) /// public static string Decode( string text ) { - // Remove these in newer version - text = text.Replace( "0D", "\r" ).Replace( "\\r", "\r" ); - text = text.Replace( "0A", "\n" ).Replace( "\\n", "\n" ); - return text; + return text.Replace( "\\r", "\r" ) + .Replace( "\\n", "\n" ) + .Replace( "%3D", "=" ); } /// @@ -55,9 +138,9 @@ public static string Decode( string text ) /// public static string Encode( string text ) { - text = text.Replace( "\r", "\\r" ); - text = text.Replace( "\n", "\\n" ); - return text; + return text.Replace( "\r", "\\r" ) + .Replace( "\n", "\\n" ) + .Replace( "=", "%3D" ); } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/AutoTranslateClient.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/AutoTranslateClient.cs deleted file mode 100644 index 42e8a6a6..00000000 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/AutoTranslateClient.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using UnityEngine; -using UnityEngine.Networking; -using XUnity.AutoTranslator.Plugin.Core.Configuration; - -namespace XUnity.AutoTranslator.Plugin.Core.Web -{ - public static class AutoTranslateClient - { - private static KnownEndpoint _endpoint; - private static int _runningTranslations = 0; - private static int _translationCount; - - public static void Configure() - { - _endpoint = KnownEndpoints.FindEndpoint( Settings.ServiceEndpoint ); - - if( _endpoint != null ) - { - _endpoint.ConfigureServicePointManager(); - } - } - - public static bool IsConfigured - { - get - { - return _endpoint != null; - } - } - - public static bool HasAvailableClients => _runningTranslations < Settings.MaxConcurrentTranslations; - - public static IEnumerator TranslateByWWW( string untranslated, string from, string to, Action success, Action failure ) - { - var url = _endpoint.GetServiceUrl( untranslated, from, to ); - var headers = new Dictionary(); - _endpoint.ApplyHeaders( headers ); - - using( var www = new WWW( url, null, headers ) ) - { - _runningTranslations++; - yield return www; - _runningTranslations--; - - _translationCount++; - if( Settings.MaxConcurrentTranslations == Settings.DefaultMaxConcurrentTranslations ) - { - if( _translationCount > Settings.MaxTranslationsBeforeSlowdown ) - { - Settings.MaxConcurrentTranslations = 1; - Console.WriteLine( "[XUnity.AutoTranslator][WARN]: Maximum translations per session reached. Entering slowdown mode." ); - } - } - - if( !Settings.IsShutdown ) - { - if( _translationCount > Settings.MaxTranslationsBeforeShutdown ) - { - Settings.IsShutdown = true; - Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: Maximum translations per session reached. Shutting plugin down." ); - } - } - - - string error = null; - try - { - error = www.error; - } - catch( Exception e ) - { - error = e.ToString(); - } - - if( error != null ) - { - failure(); - } - else - { - var text = www.text; - if( text != null ) - { - try - { - if( _endpoint.TryExtractTranslated( text, out var translatedText ) ) - { - translatedText = translatedText ?? string.Empty; - success( translatedText ); - } - else - { - failure(); - } - } - catch - { - failure(); - } - } - else - { - failure(); - } - } - } - } - } -} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/BaiduTranslateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/BaiduTranslateEndpoint.cs index 48470a4b..f4df0a7f 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/BaiduTranslateEndpoint.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/BaiduTranslateEndpoint.cs @@ -12,18 +12,15 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web { - public class BaiduTranslateEndpoint : KnownEndpoint + public class BaiduTranslateEndpoint : KnownHttpEndpoint { - private static ServicePoint ServicePoint; private static readonly string HttpServicePointTemplateUrl = "http://api.fanyi.baidu.com/api/trans/vip/translate?q={0}&from={1}&to={2}&appid={3}&salt={4}&sign={5}"; - private static readonly string HttpsServicePointTemplateUrl = "https://api.fanyi.baidu.com/api/trans/vip/translate?q={0}&from={1}&to={2}&appid={3}&salt={4}&sign={5}"; private static readonly MD5 HashMD5 = MD5.Create(); public BaiduTranslateEndpoint() - : base( KnownEndpointNames.GoogleTranslate ) { - + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "api.fanyi.baidu.com" ); } private static string CreateMD5( string input ) @@ -39,30 +36,12 @@ private static string CreateMD5( string input ) return sb.ToString().ToLower(); } - public override void ApplyHeaders( Dictionary headers ) - { - headers[ "User-Agent" ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"; - headers[ "Accept-Charset" ] = "UTF-8"; - } - public override void ApplyHeaders( WebHeaderCollection headers ) { - headers[ HttpRequestHeader.UserAgent ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"; + headers[ HttpRequestHeader.UserAgent ] = Settings.GetUserAgent( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" ); headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8"; } - public override void ConfigureServicePointManager() - { - try - { - ServicePoint = ServicePointManager.FindServicePoint( new Uri( "http://api.fanyi.baidu.com" ) ); - ServicePoint.ConnectionLimit = Settings.MaxConcurrentTranslations; - } - catch - { - } - } - public override bool TryExtractTranslated( string result, out string translated ) { try @@ -88,7 +67,9 @@ public override bool TryExtractTranslated( string result, out string translated } translated = lineBuilder.ToString(); - return true; + + var success = !string.IsNullOrEmpty( translated ); + return success; } catch( Exception ) { @@ -102,7 +83,7 @@ public override string GetServiceUrl( string untranslatedText, string from, stri string salt = DateTime.UtcNow.Millisecond.ToString(); var md5 = CreateMD5( Settings.BaiduAppId + untranslatedText + salt + Settings.BaiduAppSecret ); - return string.Format( Settings.EnableSSL ? HttpsServicePointTemplateUrl : HttpServicePointTemplateUrl, WWW.EscapeURL( untranslatedText ), from, to, Settings.BaiduAppId, salt, md5 ); + return string.Format( HttpServicePointTemplateUrl, WWW.EscapeURL( untranslatedText ), from, to, Settings.BaiduAppId, salt, md5 ); } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/DefaultEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/DefaultEndpoint.cs index 9e8d5d14..83c9e0fb 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/DefaultEndpoint.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/DefaultEndpoint.cs @@ -6,36 +6,21 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web { - public class DefaultEndpoint : KnownEndpoint + public class DefaultEndpoint : KnownHttpEndpoint { - private static ServicePoint ServicePoint; private static readonly string ServicePointTemplateUrl = "{0}?from={1}&to={2}&text={3}"; + private string _endpoint; public DefaultEndpoint( string endpoint ) - : base( endpoint ) - { - } - - public override void ApplyHeaders( Dictionary headers ) { + _endpoint = endpoint; + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( new Uri( _endpoint ).Host ); } public override void ApplyHeaders( WebHeaderCollection headers ) { } - public override void ConfigureServicePointManager() - { - try - { - ServicePoint = ServicePointManager.FindServicePoint( new Uri( Identifier ) ); - ServicePoint.ConnectionLimit = Settings.MaxConcurrentTranslations; - } - catch - { - } - } - public override bool TryExtractTranslated( string result, out string translated ) { translated = result; @@ -44,7 +29,7 @@ public override bool TryExtractTranslated( string result, out string translated public override string GetServiceUrl( string untranslatedText, string from, string to ) { - return string.Format( ServicePointTemplateUrl, Identifier, from, to, WWW.EscapeURL( untranslatedText ) ); + return string.Format( ServicePointTemplateUrl, _endpoint, from, to, WWW.EscapeURL( untranslatedText ) ); } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/ExciteTranslateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/ExciteTranslateEndpoint.cs new file mode 100644 index 00000000..f54f7e78 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/ExciteTranslateEndpoint.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using SimpleJSON; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class ExciteTranslateEndpoint : KnownWwwEndpoint + { + private static readonly string HttpsServicePointTemplateUrl = "https://www.excite.co.jp/world/?wb_lp={0}{1}&before={2}"; + + public ExciteTranslateEndpoint() + { + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "www.excite.co.jp", "excite.co.jp" ); + } + + public override void ApplyHeaders( Dictionary headers ) + { + headers[ "User-Agent" ] = Settings.GetUserAgent( "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53" ); + headers[ "Accept" ] = "text/html"; + //headers[ "Accept-Charset" ] = "UTF-8"; + //headers[ "DNT" ] = "1"; + } + + public override bool TryExtractTranslated( string result, out string translated ) + { + try + { + string extracted = result.GetBetween( "class=\"inputText\">", "

" ); + translated = RestSharp.Contrib.HttpUtility.HtmlDecode( extracted ?? string.Empty ); + + var success = !string.IsNullOrEmpty( translated ); + return success; + } + catch + { + translated = null; + return false; + } + } + + public override string GetServiceUrl( string untranslatedText, string from, string to ) + { + return string.Format( HttpsServicePointTemplateUrl, from.ToUpper(), to.ToUpper(), WWW.EscapeURL( untranslatedText ) ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateEndpoint.cs index 790c4226..6a17c27f 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateEndpoint.cs +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateEndpoint.cs @@ -1,8 +1,13 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Net; +using System.Reflection; using System.Text; +using Harmony; +using Jurassic; using SimpleJSON; using UnityEngine; using XUnity.AutoTranslator.Plugin.Core.Configuration; @@ -11,49 +16,282 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web { - public class GoogleTranslateEndpoint : KnownEndpoint + public class GoogleTranslateEndpoint : KnownHttpEndpoint { - //private static readonly string CertificateIssuer = "CN=Google Internet Authority G3, O=Google Trust Services, C=US"; - private static ServicePoint ServicePoint; - private static readonly string HttpServicePointTemplateUrl = "http://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}"; - private static readonly string HttpsServicePointTemplateUrl = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}"; + //protected static readonly ConstructorInfo WwwConstructor = Constants.Types.WWW?.GetConstructor( new[] { typeof( string ), typeof( byte[] ), typeof( Dictionary ) } ); + private static readonly string HttpsServicePointTemplateUrl = "https://translate.googleapis.com/translate_a/single?client=t&dt=t&sl={0}&tl={1}&ie=UTF-8&oe=UTF-8&tk={2}&q={3}"; + private static readonly string HttpsTranslateUserSite = "https://translate.google.com"; + private static readonly string DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"; + //private static readonly string UserAgentRepository = "https://techblog.willshouse.com/2012/01/03/most-common-user-agents/"; + private static readonly System.Random RandomNumbers = new System.Random(); + + private static readonly string[] Accepts = new string[] { null, "*/*", "application/json" }; + private static readonly string[] AcceptLanguages = new string[] { null, "en-US,en;q=0.9", "en-US", "en" }; + private static readonly string[] Referers = new string[] { null, "https://translate.google.com/" }; + private static readonly string[] AcceptCharsets = new string[] { null, Encoding.UTF8.WebName }; + + private static readonly string Accept = Accepts[ RandomNumbers.Next( Accepts.Length ) ]; + private static readonly string AcceptLanguage = AcceptLanguages[ RandomNumbers.Next( AcceptLanguages.Length ) ]; + private static readonly string Referer = Referers[ RandomNumbers.Next( Referers.Length ) ]; + private static readonly string AcceptCharset = AcceptCharsets[ RandomNumbers.Next( AcceptCharsets.Length ) ]; + + private CookieContainer _cookieContainer; + private bool _hasSetup = false; + //private bool _hasSetupCustomUserAgent = false; + //private string _popularUserAgent; + private long m = 425635; + private long s = 1953544246; public GoogleTranslateEndpoint() - : base( KnownEndpointNames.GoogleTranslate ) { + _cookieContainer = new CookieContainer(); + // Configure service points / service point manager + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translate.google.com", "translate.googleapis.com" ); + SetupServicePoints( "https://translate.googleapis.com", "https://translate.google.com" ); } - public override void ApplyHeaders( Dictionary headers ) + public override bool SupportsLineSplitting => true; + + public override void ApplyHeaders( WebHeaderCollection headers ) { - headers[ "User-Agent" ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"; - headers[ "Accept" ] = "*/*"; - headers[ "Accept-Charset" ] = "UTF-8"; + headers[ HttpRequestHeader.UserAgent ] = Settings.GetUserAgent( DefaultUserAgent ); + + if( AcceptLanguage != null ) + { + headers[ HttpRequestHeader.AcceptLanguage ] = AcceptLanguage; + } + if( Accept != null ) + { + headers[ HttpRequestHeader.Accept ] = Accept; + } + if( Referer != null ) + { + headers[ HttpRequestHeader.Referer ] = Referer; + } + if( AcceptCharset != null ) + { + headers[ HttpRequestHeader.AcceptCharset ] = AcceptCharset; + } } - public override void ApplyHeaders( WebHeaderCollection headers ) + public override IEnumerator OnBeforeTranslate( int translationCount ) { - headers[ HttpRequestHeader.UserAgent ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"; - headers[ HttpRequestHeader.Accept ] = "*/*"; - headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8"; + //if( !_hasSetupCustomUserAgent ) + //{ + // _hasSetupCustomUserAgent = true; + + // // setup dynamic user agent + // var enumerator = SetupDynamicUserAgent(); + // while( enumerator.MoveNext() ) + // { + // yield return enumerator.Current; + // } + //} + + if( !_hasSetup || translationCount % 100 == 0 ) + { + _hasSetup = true; + + // Setup TKK and cookies + var enumerator = SetupTKK(); + while( enumerator.MoveNext() ) + { + yield return enumerator.Current; + } + + } } - public override void ConfigureServicePointManager() + //public IEnumerator SetupDynamicUserAgent() + //{ + // // have to use WWW for this because unity mono is broken + + // if( WwwConstructor != null ) + // { + // object www; + // try + // { + // var headers = new Dictionary(); + // www = WwwConstructor.Invoke( new object[] { UserAgentRepository, null, headers } ); + // } + // catch( Exception e ) + // { + // Logger.Current.Warn( e, "An error occurred while retrieving dynamic user agent." ); + // yield break; + // } + + // yield return www; + + // try + // { + // var error = (string)AccessTools.Property( Constants.Types.WWW, "error" ).GetValue( www, null ); + // if( error == null ) + // { + // var text = (string)AccessTools.Property( Constants.Types.WWW, "text" ).GetValue( www, null ); + // var userAgents = text.GetBetween( "" ); + // if( userAgents.Length > 42 ) + // { + // var reader = new StringReader( userAgents ); + // var popularUserAgent = reader.ReadLine(); + // if( popularUserAgent.Length > 30 && popularUserAgent.Length < 300 && popularUserAgent.StartsWith( "Mozilla/" ) ) + // { + // _popularUserAgent = popularUserAgent; + // } + // else + // { + // Logger.Current.Warn( "An error occurred while retrieving dynamic user agent. Could not find a user agent in returned html." ); + // } + // } + // else + // { + // Logger.Current.Warn( "An error occurred while retrieving dynamic user agent. Could not find a user agent in returned html." ); + // } + // } + // else + // { + // Logger.Current.Warn( "An error occurred while retrieving dynamic user agent. Request failed: " + Environment.NewLine + error ); + // } + // } + // catch( Exception e ) + // { + // Logger.Current.Warn( e, "An error occurred while retrieving dynamic user agent." ); + // } + // } + //} + + public IEnumerator SetupTKK() { + string error = null; + DownloadResult downloadResult = null; + + _cookieContainer = new CookieContainer(); + + var client = GetClient(); try { - //ServicePointManager.ServerCertificateValidationCallback += ( sender, certificate, chain, sslPolicyErrors ) => - //{ - // return certificate.Issuer == CertificateIssuer; - //}; - - ServicePoint = ServicePointManager.FindServicePoint( new Uri( "http://translate.googleapis.com" ) ); - ServicePoint.ConnectionLimit = Settings.MaxConcurrentTranslations; - + ApplyHeaders( client.Headers ); + client.Headers.Remove( HttpRequestHeader.Referer ); + downloadResult = client.GetDownloadResult( new Uri( HttpsTranslateUserSite ) ); } - catch + catch( Exception e ) { + error = e.ToString(); } + + if( downloadResult != null ) + { + if( Features.SupportsCustomYieldInstruction ) + { + yield return downloadResult; + } + else + { + while( !downloadResult.IsCompleted ) + { + yield return new WaitForSeconds( 0.2f ); + } + } + + error = downloadResult.Error; + if( downloadResult.Succeeded && downloadResult.Result != null ) + { + try + { + var html = downloadResult.Result; + + const string lookup = "TKK=eval('"; + var lookupIndex = html.IndexOf( lookup ) + lookup.Length; + var openClamIndex = html.IndexOf( '{', lookupIndex ); + var closeClamIndex = html.IndexOf( '}', openClamIndex ); + var functionIndex = html.IndexOf( "function", lookupIndex ); + var script = html.Substring( functionIndex, closeClamIndex - functionIndex + 1 ); + var decodedScript = script.Replace( "\\x3d", "=" ).Replace( "\\x27", "'" ).Replace( "function", "function FuncName" ); + + // https://github.com/paulbartrum/jurassic/wiki/Safely-executing-user-provided-scripts + ScriptEngine engine = new ScriptEngine(); + engine.Evaluate( decodedScript ); + var result = engine.CallGlobalFunction( "FuncName" ); + + var parts = result.Split( '.' ); + m = long.Parse( parts[ 0 ] ); + s = long.Parse( parts[ 1 ] ); + } + catch( Exception e ) + { + error = e.ToString(); + } + } + } + + if( error != null ) + { + Logger.Current.Error( "An error occurred while setting up GoogleTranslate Cookie/TKK." + Environment.NewLine + error ); + } + } + + // TKK Approach stolen from Translation Aggregator r190, all credits to Sinflower + + private long Vi( long r, string o ) + { + for( var t = 0 ; t < o.Length ; t += 3 ) + { + long a = o[ t + 2 ]; + a = a >= 'a' ? a - 87 : a - '0'; + a = '+' == o[ t + 1 ] ? r >> (int)a : r << (int)a; + r = '+' == o[ t ] ? r + a & 4294967295 : r ^ a; + } + + return r; + } + + private string Tk( string r ) + { + List S = new List(); + + for( var v = 0 ; v < r.Length ; v++ ) + { + long A = r[ v ]; + if( 128 > A ) + S.Add( A ); + else + { + if( 2048 > A ) + S.Add( A >> 6 | 192 ); + else if( 55296 == ( 64512 & A ) && v + 1 < r.Length && 56320 == ( 64512 & r[ v + 1 ] ) ) + { + A = 65536 + ( ( 1023 & A ) << 10 ) + ( 1023 & r[ ++v ] ); + S.Add( A >> 18 | 240 ); + S.Add( A >> 12 & 63 | 128 ); + } + else + { + S.Add( A >> 12 | 224 ); + S.Add( A >> 6 & 63 | 128 ); + } + + S.Add( 63 & A | 128 ); + } + } + + const string F = "+-a^+6"; + const string D = "+-3^+b+-f"; + long p = m; + + for( var b = 0 ; b < S.Count ; b++ ) + { + p += S[ b ]; + p = Vi( p, F ); + } + + p = Vi( p, D ); + p ^= s; + if( 0 > p ) + p = ( 2147483647 & p ) + 2147483648; + + p %= (long)1e6; + + return p.ToString( CultureInfo.InvariantCulture ) + "." + ( p ^ m ).ToString( CultureInfo.InvariantCulture ); } public override bool TryExtractTranslated( string result, out string translated ) @@ -74,7 +312,9 @@ public override bool TryExtractTranslated( string result, out string translated } translated = lineBuilder.ToString(); - return true; + + var success = !string.IsNullOrEmpty( translated ); + return success; } catch { @@ -85,7 +325,24 @@ public override bool TryExtractTranslated( string result, out string translated public override string GetServiceUrl( string untranslatedText, string from, string to ) { - return string.Format( Settings.EnableSSL ? HttpsServicePointTemplateUrl : HttpServicePointTemplateUrl, from, to, WWW.EscapeURL( untranslatedText ) ); + return string.Format( HttpsServicePointTemplateUrl, from, to, Tk( untranslatedText ), WWW.EscapeURL( untranslatedText ) ); + } + + public override void WriteCookies( HttpWebResponse response ) + { + CookieCollection cookies = response.Cookies; + foreach( Cookie cookie in cookies ) + { + // redirect cookie to correct domain + cookie.Domain = ".googleapis.com"; + } + + _cookieContainer.Add( cookies ); + } + + public override CookieContainer ReadCookies() + { + return _cookieContainer; } } } diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateHackEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateHackEndpoint.cs new file mode 100644 index 00000000..66315a5a --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateHackEndpoint.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using SimpleJSON; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class GoogleTranslateHackEndpoint : KnownHttpEndpoint + { + private static readonly string HttpsServicePointTemplateUrl = "https://translate.google.com/m?hl=pl&sl={0}&tl={1}&ie=UTF-8&q={2}"; + + public GoogleTranslateHackEndpoint() + { + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translate.google.com" ); + } + + public override void ApplyHeaders( WebHeaderCollection headers ) + { + headers[ HttpRequestHeader.UserAgent ] = Settings.GetUserAgent( "Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.21214/28.2725; U; en) Presto/2.8.119 Version/11.10" ); + headers[ HttpRequestHeader.Accept ] = "*/*"; + headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8"; + } + + public override bool TryExtractTranslated( string result, out string translated ) + { + try + { + + String extracted = result.GetBetween( "class=\"t0\">", "" ); + translated = RestSharp.Contrib.HttpUtility.HtmlDecode( extracted ?? string.Empty ); + + var success = !string.IsNullOrEmpty( translated ); + return success; + } + catch + { + translated = null; + return false; + } + } + + public override string GetServiceUrl( string untranslatedText, string from, string to ) + { + return string.Format( HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL( untranslatedText ) ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateLegitimateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateLegitimateEndpoint.cs new file mode 100644 index 00000000..86ba5ff4 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateLegitimateEndpoint.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using Harmony; +using Jurassic; +using SimpleJSON; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class GoogleTranslateLegitimateEndpoint : KnownHttpEndpoint + { + private static readonly string HttpsServicePointTemplateUrl = "https://translation.googleapis.com/language/translate/v2?key={0}"; + + public GoogleTranslateLegitimateEndpoint() + { + // Configure service points / service point manager + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translation.googleapis.com" ); + SetupServicePoints( "https://translation.googleapis.com" ); + } + + public override bool SupportsLineSplitting => true; + + public override void ApplyHeaders( WebHeaderCollection headers ) + { + } + + public override bool TryExtractTranslated( string result, out string translated ) + { + try + { + var obj = JSON.Parse( result ); + var lineBuilder = new StringBuilder( result.Length ); + + foreach( JSONNode entry in obj.AsObject[ "data" ].AsObject[ "translations" ].AsArray ) + { + var token = entry.AsObject[ "translatedText" ].ToString(); + token = token.Substring( 1, token.Length - 2 ).UnescapeJson(); + + if( !lineBuilder.EndsWithWhitespaceOrNewline() ) lineBuilder.Append( "\n" ); + + lineBuilder.Append( token ); + } + + translated = lineBuilder.ToString(); + + var success = !string.IsNullOrEmpty( translated ); + return success; + } + catch + { + translated = null; + return false; + } + } + + public override string GetServiceUrl( string untranslatedText, string from, string to ) + { + return string.Format( HttpsServicePointTemplateUrl, WWW.EscapeURL( Settings.GoogleAPIKey ) ); + } + + public override string GetRequestObject( string untranslatedText, string from, string to ) + { + var b = new StringBuilder(); + b.Append( "{" ); + b.Append( "\"q\":\"" ).Append( untranslatedText.EscapeJson() ).Append( "\"," ); + b.Append( "\"target\":\"" ).Append( to ).Append( "\"," ); + b.Append( "\"source\":\"" ).Append( from ).Append( "\"," ); + b.Append( "\"format\":\"text\"" ); + b.Append( "}" ); + return b.ToString(); + } + + public override bool ShouldGetSecondChanceAfterFailure() + { + return false; + } + } + + //public class GRequest + //{ + // public string q { get; set; } + + // public string target { get; set; } + + // public string source { get; set; } + + // public string format { get; set; } + //} + + //public class GResponse + //{ + // public GData data { get; set; } + //} + + //public class GData + //{ + // public List translations { get; set; } + //} + + //public class GTranslation + //{ + // public string translatedText { get; set; } + //} +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoint.cs deleted file mode 100644 index 77441b76..00000000 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoint.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; - -namespace XUnity.AutoTranslator.Plugin.Core.Web -{ - public abstract class KnownEndpoint - { - public KnownEndpoint( string identifier ) - { - Identifier = identifier; - } - - public string Identifier { get; } - - public abstract void ConfigureServicePointManager(); - - public abstract string GetServiceUrl( string untranslatedText, string from, string to ); - - public abstract void ApplyHeaders( Dictionary headers ); - - public abstract void ApplyHeaders( WebHeaderCollection headers ); - - public abstract bool TryExtractTranslated( string result, out string translated ); - } -} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoints.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoints.cs deleted file mode 100644 index f66fddc9..00000000 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoints.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using XUnity.AutoTranslator.Plugin.Core.Constants; - -namespace XUnity.AutoTranslator.Plugin.Core.Web -{ - public static class KnownEndpoints - { - public static readonly KnownEndpoint GoogleTranslate = new GoogleTranslateEndpoint(); - public static readonly KnownEndpoint BaiduTranslate = new BaiduTranslateEndpoint(); - - public static KnownEndpoint FindEndpoint( string identifier ) - { - if( string.IsNullOrEmpty( identifier ) ) return null; - - switch( identifier ) - { - case KnownEndpointNames.GoogleTranslate: - return GoogleTranslate; - case KnownEndpointNames.BaiduTranslate: - return BaiduTranslate; - default: - return new DefaultEndpoint( identifier ); - } - } - } -} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownHttpEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownHttpEndpoint.cs new file mode 100644 index 00000000..efd00588 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownHttpEndpoint.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections; +using System.Net; +using System.Threading; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public abstract class KnownHttpEndpoint : IKnownEndpoint + { + private static readonly TimeSpan MaxUnusedLifespan = TimeSpan.FromSeconds( 50 ); + + private ServicePoint[] _servicePoints; + private bool _isBusy = false; + private UnityWebClient _client; + private DateTime? _clientLastUse = null; + + public KnownHttpEndpoint() + { + } + + public bool IsBusy => _isBusy; + + public virtual bool SupportsLineSplitting + { + get + { + return false; + } + } + + protected void SetupServicePoints( params string[] endpoints ) + { + _servicePoints = new ServicePoint[ endpoints.Length ]; + + for( int i = 0 ; i < endpoints.Length ; i++ ) + { + var endpoint = endpoints[ i ]; + var servicePoint = ServicePointManager.FindServicePoint( new Uri( endpoint ) ); + _servicePoints[ i ] = servicePoint; + } + } + + public IEnumerator Translate( string untranslatedText, string from, string to, Action success, Action failure ) + { + _isBusy = true; + try + { + var setup = OnBeforeTranslate( Settings.TranslationCount ); + if( setup != null ) + { + while( setup.MoveNext() ) + { + yield return setup.Current; + } + } + Logger.Current.Debug( "Starting translation for: " + untranslatedText ); + DownloadResult downloadResult = null; + try + { + var client = GetClient(); + var url = GetServiceUrl( untranslatedText, from, to ); + var request = GetRequestObject( untranslatedText, from, to ); + ApplyHeaders( client.Headers ); + + if( request != null ) + { + downloadResult = client.GetDownloadResult( new Uri( url ), request ); + } + else + { + downloadResult = client.GetDownloadResult( new Uri( url ) ); + } + } + catch( Exception e ) + { + Logger.Current.Error( e, "Error occurred while setting up translation request." ); + } + + if( downloadResult != null ) + { + if( Features.SupportsCustomYieldInstruction ) + { + yield return downloadResult; + } + else + { + while( !downloadResult.IsCompleted ) + { + yield return new WaitForSeconds( 0.2f ); + } + } + + try + { + if( downloadResult.Succeeded && downloadResult.Result != null ) + { + if( TryExtractTranslated( downloadResult.Result, out var translatedText ) ) + { + Logger.Current.Debug( $"Translation for '{untranslatedText}' succeded. Result: {translatedText}" ); + + translatedText = translatedText ?? string.Empty; + success( translatedText ); + } + else + { + Logger.Current.Error( "Error occurred while extracting translation." ); + failure(); + } + } + else + { + Logger.Current.Error( "Error occurred while retrieving translation." + Environment.NewLine + downloadResult.Error ); + failure(); + } + } + catch( Exception e ) + { + Logger.Current.Error( e, "Error occurred while retrieving translation." ); + failure(); + } + } + else + { + failure(); + } + } + finally + { + _clientLastUse = DateTime.UtcNow; + _isBusy = false; + } + } + + public virtual void OnUpdate() + { + if( !_isBusy && _clientLastUse.HasValue && DateTime.UtcNow - _clientLastUse > MaxUnusedLifespan && !_client.IsBusy + && _servicePoints != null && _servicePoints.Length > 0 ) + { + Logger.Current.Debug( $"Closing service points because they were not used for {(int)MaxUnusedLifespan.TotalSeconds} seconds." ); + + _isBusy = true; + _clientLastUse = null; + + ThreadPool.QueueUserWorkItem( delegate ( object state ) + { + // never do a job like this on the game loop thread + try + { + foreach( var servicePoint in _servicePoints ) + { + servicePoint.CloseConnectionGroup( MyWebClient.ConnectionGroupName ); + } + } + finally + { + _isBusy = false; + } + } ); + } + } + + public virtual bool ShouldGetSecondChanceAfterFailure() + { + return false; + } + + public abstract string GetServiceUrl( string untranslatedText, string from, string to ); + + public abstract void ApplyHeaders( WebHeaderCollection headers ); + + public abstract bool TryExtractTranslated( string result, out string translated ); + + public virtual string GetRequestObject( string untranslatedText, string from, string to ) + { + return null; + } + + public virtual void WriteCookies( HttpWebResponse response ) + { + + } + + public virtual CookieContainer ReadCookies() + { + return null; + } + + public virtual IEnumerator OnBeforeTranslate( int translationCount ) + { + return null; + } + + public UnityWebClient GetClient() + { + if( _client == null ) + { + _client = new UnityWebClient( this ); + _clientLastUse = DateTime.UtcNow; + } + return _client; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownWwwEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownWwwEndpoint.cs new file mode 100644 index 00000000..6c40f0cf --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/KnownWwwEndpoint.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using Harmony; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public abstract class KnownWwwEndpoint : IKnownEndpoint + { + protected static readonly ConstructorInfo WwwConstructor = Constants.Types.WWW.GetConstructor( new[] { typeof( string ), typeof( byte[] ), typeof( Dictionary ) } ); + + private bool _isBusy = false; + + public KnownWwwEndpoint() + { + } + + public bool IsBusy => _isBusy; + + public virtual bool SupportsLineSplitting + { + get + { + return false; + } + } + + public IEnumerator Translate( string untranslatedText, string from, string to, Action success, Action failure ) + { + _isBusy = true; + try + { + var setup = OnBeforeTranslate( Settings.TranslationCount ); + if( setup != null ) + { + while( setup.MoveNext() ) + { + yield return setup.Current; + } + } + + Logger.Current.Debug( "Starting translation for: " + untranslatedText ); + object www = null; + try + { + var headers = new Dictionary(); + ApplyHeaders( headers ); + var url = GetServiceUrl( untranslatedText, from, to ); + www = WwwConstructor.Invoke( new object[] { url, null, headers } ); + } + catch( Exception e ) + { + Logger.Current.Error( e, "Error occurred while setting up translation request." ); + } + + if( www != null ) + { + yield return www; + + try + { + string error = null; + try + { + error = (string)AccessTools.Property( Constants.Types.WWW, "error" ).GetValue( www, null ); + } + catch( Exception e ) + { + error = e.ToString(); + } + + if( error != null ) + { + Logger.Current.Error( "Error occurred while retrieving translation." + Environment.NewLine + error ); + failure(); + } + else + { + var text = (string)AccessTools.Property( Constants.Types.WWW, "text" ).GetValue( www, null ); + + if( text != null ) + { + if( TryExtractTranslated( text, out var translatedText ) ) + { + Logger.Current.Debug( $"Translation for '{untranslatedText}' succeded. Result: {translatedText}" ); + + translatedText = translatedText ?? string.Empty; + success( translatedText ); + } + else + { + Logger.Current.Error( "Error occurred while extracting translation." ); + failure(); + } + } + else + { + Logger.Current.Error( "Error occurred while extracting text from response." ); + failure(); + } + } + } + catch( Exception e ) + { + Logger.Current.Error( e, "Error occurred while retrieving translation." ); + failure(); + } + } + else + { + failure(); + } + } + finally + { + _isBusy = false; + } + } + + public virtual void OnUpdate() + { + } + + public virtual bool ShouldGetSecondChanceAfterFailure() + { + return false; + } + + public abstract string GetServiceUrl( string untranslatedText, string from, string to ); + + public abstract void ApplyHeaders( Dictionary headers ); + + public abstract bool TryExtractTranslated( string result, out string translated ); + + public virtual IEnumerator OnBeforeTranslate( int translationCount ) + { + return null; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/MyWebClient.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/MyWebClient.cs new file mode 100644 index 00000000..9c839670 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/MyWebClient.cs @@ -0,0 +1,1715 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Cache; +using System.Reflection; +using System.Text; +using System.Threading; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public delegate void MyDownloadStringCompletedEventHandler( object sender, MyDownloadStringCompletedEventArgs e ); + public delegate void MyUploadStringCompletedEventHandler( object sender, MyUploadStringCompletedEventArgs e ); + + public class MyDownloadStringCompletedEventArgs : AsyncCompletedEventArgs + { + private string result; + + internal MyDownloadStringCompletedEventArgs( string result, Exception error, bool cancelled, object userState ) : base( error, cancelled, userState ) + { + this.result = result; + } + + public string Result + { + get + { + base.RaiseExceptionIfNecessary(); + return this.result; + } + } + } + public class MyUploadStringCompletedEventArgs : AsyncCompletedEventArgs + { + private string result; + + internal MyUploadStringCompletedEventArgs( string result, Exception error, bool cancelled, object userState ) : base( error, cancelled, userState ) + { + this.result = result; + } + + public string Result + { + get + { + base.RaiseExceptionIfNecessary(); + return this.result; + } + } + } + + public class MyAsyncCompletedEventArgs : EventArgs + { + private bool _cancelled; + private Exception _error; + private object _userState; + + public MyAsyncCompletedEventArgs( Exception error, bool cancelled, object userState ) + { + this._error = error; + this._cancelled = cancelled; + this._userState = userState; + } + + protected void RaiseExceptionIfNecessary() + { + if( this._error != null ) + { + throw new TargetInvocationException( this._error ); + } + if( this._cancelled ) + { + throw new InvalidOperationException( "The operation was cancelled" ); + } + } + + public bool Cancelled + { + get + { + return this._cancelled; + } + } + + public Exception Error + { + get + { + return this._error; + } + } + + public object UserState + { + get + { + return this._userState; + } + } + } + + public class MyWebClient + { + public static readonly string ConnectionGroupName = Guid.NewGuid().ToString(); + + private bool async; + private Uri baseAddress; + private string baseString; + private ICredentials credentials; + private System.Text.Encoding encoding = System.Text.Encoding.Default; + private WebHeaderCollection headers; + private static byte[] hexBytes = new byte[ 0x10 ]; + private bool is_busy; + private IWebProxy proxy; + private NameValueCollection queryString; + private WebHeaderCollection responseHeaders; + private static readonly string urlEncodedCType = "application/x-www-form-urlencoded"; + + public event MyDownloadStringCompletedEventHandler DownloadStringCompleted; + public event MyUploadStringCompletedEventHandler UploadStringCompleted; + + static MyWebClient() + { + int index = 0; + int num2 = 0x30; + while( num2 <= 0x39 ) + { + hexBytes[ index ] = (byte)num2; + num2++; + index++; + } + int num3 = 0x61; + while( num3 <= 0x66 ) + { + hexBytes[ index ] = (byte)num3; + num3++; + index++; + } + } + + //public void CancelAsync() + //{ + // MyWebClient client = this; + // lock( client ) + // { + // if( this.async_thread != null ) + // { + // Thread thread = this.async_thread; + // this.CompleteAsync(); + // thread.Interrupt(); + // } + // } + //} + + private void CheckBusy() + { + if( this.IsBusy ) + { + throw new NotSupportedException( "WebClient does not support conccurent I/O operations." ); + } + } + + private void CompleteAsync() + { + MyWebClient client = this; + lock( client ) + { + this.is_busy = false; + } + } + + private Uri CreateUri( string address ) + { + return this.MakeUri( address ); + } + + private Uri CreateUri( Uri address ) + { + string query = address.Query; + if( string.IsNullOrEmpty( query ) ) + { + query = this.GetQueryString( true ); + } + if( ( this.baseAddress == null ) && ( query == null ) ) + { + return address; + } + if( this.baseAddress == null ) + { + return new Uri( address.ToString() + query, query != null ); + } + if( query == null ) + { + return new Uri( this.baseAddress, address.ToString() ); + } + return new Uri( this.baseAddress, address.ToString() + query, query != null ); + } + + private string DetermineMethod( Uri address, string method, bool is_upload ) + { + if( method != null ) + { + return method; + } + if( address.Scheme == Uri.UriSchemeFtp ) + { + return ( !is_upload ? "RETR" : "STOR" ); + } + return ( !is_upload ? "GET" : "POST" ); + } + + public byte[] DownloadData( string address ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.DownloadData( this.CreateUri( address ) ); + } + + public byte[] DownloadData( Uri address ) + { + byte[] buffer; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + try + { + this.SetBusy(); + this.async = false; + buffer = this.DownloadDataCore( address, null ); + } + finally + { + this.is_busy = false; + } + return buffer; + } + + //public void DownloadDataAsync( Uri address ) + //{ + // this.DownloadDataAsync( address, null ); + //} + + //public void DownloadDataAsync( Uri address, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // try + // { + // byte[] result = this.DownloadDataCore( (Uri)objArray[ 0 ], objArray[ 1 ] ); + // this.OnDownloadDataCompleted( new DownloadDataCompletedEventArgs( result, null, false, objArray[ 1 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // this.OnDownloadDataCompleted( new DownloadDataCompletedEventArgs( null, null, true, objArray[ 1 ] ) ); + // throw; + // } + // catch( Exception exception ) + // { + // this.OnDownloadDataCompleted( new DownloadDataCompletedEventArgs( null, exception, false, objArray[ 1 ] ) ); + // } + // }, parameter ); + // } + //} + + private byte[] DownloadDataCore( Uri address, object userToken ) + { + WebRequest request = null; + byte[] buffer; + try + { + request = this.SetupRequest( address ); + WebResponse webResponse = this.GetWebResponse( request ); + Stream responseStream = webResponse.GetResponseStream(); + buffer = this.ReadAll( responseStream, (int)webResponse.ContentLength, userToken ); + responseStream.Close(); + webResponse.Close(); + } + catch( ThreadInterruptedException ) + { + if( request != null ) + { + request.Abort(); + } + throw; + } + catch( WebException ) + { + throw; + } + catch( Exception exception2 ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + } + return buffer; + } + + //public void DownloadFile( string address, string fileName ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // this.DownloadFile( this.CreateUri( address ), fileName ); + //} + + //public void DownloadFile( Uri address, string fileName ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // if( fileName == null ) + // { + // throw new ArgumentNullException( "fileName" ); + // } + // try + // { + // this.SetBusy(); + // this.async = false; + // this.DownloadFileCore( address, fileName, null ); + // } + // catch( WebException ) + // { + // throw; + // } + // catch( Exception exception2 ) + // { + // throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + // } + // finally + // { + // this.is_busy = false; + // } + //} + + //public void DownloadFileAsync( Uri address, string fileName ) + //{ + // this.DownloadFileAsync( address, fileName, null ); + //} + + //public void DownloadFileAsync( Uri address, string fileName, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // if( fileName == null ) + // { + // throw new ArgumentNullException( "fileName" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, fileName, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // try + // { + // this.DownloadFileCore( (Uri)objArray[ 0 ], (string)objArray[ 1 ], objArray[ 2 ] ); + // this.OnDownloadFileCompleted( new AsyncCompletedEventArgs( null, false, objArray[ 2 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // this.OnDownloadFileCompleted( new AsyncCompletedEventArgs( null, true, objArray[ 2 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnDownloadFileCompleted( new AsyncCompletedEventArgs( exception, false, objArray[ 2 ] ) ); + // } + // }, parameter ); + // } + //} + + //private void DownloadFileCore( Uri address, string fileName, object userToken ) + //{ + // WebRequest request = null; + // FileStream stream = new FileStream( fileName, FileMode.Create ); + // try + // { + // request = this.SetupRequest( address ); + // WebResponse webResponse = this.GetWebResponse( request ); + // Stream responseStream = webResponse.GetResponseStream(); + // int contentLength = (int)webResponse.ContentLength; + // int count = ( ( contentLength > -1 ) && ( contentLength <= 0x8000 ) ) ? contentLength : 0x8000; + // byte[] buffer = new byte[ count ]; + // int num3 = 0; + // long bytesReceived = 0L; + // while( ( num3 = responseStream.Read( buffer, 0, count ) ) != 0 ) + // { + // if( this.async ) + // { + // bytesReceived += num3; + // this.OnDownloadProgressChanged( new DownloadProgressChangedEventArgs( bytesReceived, webResponse.ContentLength, userToken ) ); + // } + // stream.Write( buffer, 0, num3 ); + // } + // } + // catch( ThreadInterruptedException ) + // { + // if( request != null ) + // { + // request.Abort(); + // } + // throw; + // } + // finally + // { + // if( stream != null ) + // { + // stream.Dispose(); + // } + // } + //} + + public string DownloadString( string address ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.encoding.GetString( this.DownloadData( this.CreateUri( address ) ) ); + } + + public string DownloadString( Uri address ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.encoding.GetString( this.DownloadData( this.CreateUri( address ) ) ); + } + + public void DownloadStringAsync( Uri address ) + { + this.DownloadStringAsync( address, null ); + } + + public void DownloadStringAsync( Uri address, object userToken ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + MyWebClient client = this; + lock( client ) + { + this.SetBusy(); + this.async = true; + object[] parameter = new object[] { address, userToken }; + ThreadPool.QueueUserWorkItem( delegate ( object state ) + { + object[] objArray = (object[])state; + try + { + string result = this.encoding.GetString( this.DownloadDataCore( (Uri)objArray[ 0 ], objArray[ 1 ] ) ); + this.OnDownloadStringCompleted( new MyDownloadStringCompletedEventArgs( result, null, false, objArray[ 1 ] ) ); + } + catch( ThreadInterruptedException ) + { + this.OnDownloadStringCompleted( new MyDownloadStringCompletedEventArgs( null, null, true, objArray[ 1 ] ) ); + } + catch( Exception exception ) + { + this.OnDownloadStringCompleted( new MyDownloadStringCompletedEventArgs( null, exception, false, objArray[ 1 ] ) ); + } + }, parameter ); + } + } + + private static Exception GetMustImplement() + { + return new NotImplementedException(); + } + + private string GetQueryString( bool add_qmark ) + { + if( ( this.queryString == null ) || ( this.queryString.Count == 0 ) ) + { + return null; + } + StringBuilder builder = new StringBuilder(); + if( add_qmark ) + { + builder.Append( '?' ); + } + IEnumerator enumerator = this.queryString.GetEnumerator(); + try + { + while( enumerator.MoveNext() ) + { + string current = (string)enumerator.Current; + builder.AppendFormat( "{0}={1}&", current, this.UrlEncode( this.queryString[ current ] ) ); + } + } + finally + { + IDisposable disposable = enumerator as IDisposable; + if( disposable != null ) + { + disposable.Dispose(); + } + } + if( builder.Length != 0 ) + { + builder.Length--; + } + if( builder.Length == 0 ) + { + return null; + } + return builder.ToString(); + } + + protected virtual WebRequest GetWebRequest( Uri address ) + { + return WebRequest.Create( address ); + } + + protected virtual WebResponse GetWebResponse( WebRequest request ) + { + WebResponse response = request.GetResponse(); + this.responseHeaders = response.Headers; + return response; + } + + protected virtual WebResponse GetWebResponse( WebRequest request, IAsyncResult result ) + { + WebResponse response = request.EndGetResponse( result ); + this.responseHeaders = response.Headers; + return response; + } + + private Uri MakeUri( string path ) + { + string queryString = this.GetQueryString( true ); + if( ( this.baseAddress == null ) && ( queryString == null ) ) + { + try + { + return new Uri( path ); + } + catch( ArgumentNullException ) + { + path = Path.GetFullPath( path ); + return new Uri( "file://" + path ); + } + catch( UriFormatException ) + { + path = Path.GetFullPath( path ); + return new Uri( "file://" + path ); + } + } + if( this.baseAddress == null ) + { + return new Uri( path + queryString, queryString != null ); + } + if( queryString == null ) + { + return new Uri( this.baseAddress, path ); + } + return new Uri( this.baseAddress, path + queryString, queryString != null ); + } + + //protected virtual void OnDownloadDataCompleted( DownloadDataCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.DownloadDataCompleted != null ) + // { + // this.DownloadDataCompleted( this, args ); + // } + //} + + //protected virtual void OnDownloadFileCompleted( AsyncCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.DownloadFileCompleted != null ) + // { + // this.DownloadFileCompleted( this, args ); + // } + //} + + //protected virtual void OnDownloadProgressChanged( DownloadProgressChangedEventArgs e ) + //{ + // if( this.DownloadProgressChanged != null ) + // { + // this.DownloadProgressChanged( this, e ); + // } + //} + + protected virtual void OnDownloadStringCompleted( MyDownloadStringCompletedEventArgs args ) + { + this.CompleteAsync(); + if( this.DownloadStringCompleted != null ) + { + this.DownloadStringCompleted( this, args ); + } + } + + //protected virtual void OnOpenReadCompleted( OpenReadCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.OpenReadCompleted != null ) + // { + // this.OpenReadCompleted( this, args ); + // } + //} + + //protected virtual void OnOpenWriteCompleted( OpenWriteCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.OpenWriteCompleted != null ) + // { + // this.OpenWriteCompleted( this, args ); + // } + //} + + //protected virtual void OnUploadDataCompleted( UploadDataCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.UploadDataCompleted != null ) + // { + // this.UploadDataCompleted( this, args ); + // } + //} + + //protected virtual void OnUploadFileCompleted( UploadFileCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.UploadFileCompleted != null ) + // { + // this.UploadFileCompleted( this, args ); + // } + //} + + //protected virtual void OnUploadProgressChanged( UploadProgressChangedEventArgs e ) + //{ + // if( this.UploadProgressChanged != null ) + // { + // this.UploadProgressChanged( this, e ); + // } + //} + + protected virtual void OnUploadStringCompleted( MyUploadStringCompletedEventArgs args ) + { + this.CompleteAsync(); + if( this.UploadStringCompleted != null ) + { + this.UploadStringCompleted( this, args ); + } + } + + //protected virtual void OnUploadValuesCompleted( UploadValuesCompletedEventArgs args ) + //{ + // this.CompleteAsync(); + // if( this.UploadValuesCompleted != null ) + // { + // this.UploadValuesCompleted( this, args ); + // } + //} + + public Stream OpenRead( string address ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.OpenRead( this.CreateUri( address ) ); + } + + public Stream OpenRead( Uri address ) + { + Stream responseStream; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + WebRequest request = null; + try + { + this.SetBusy(); + this.async = false; + request = this.SetupRequest( address ); + responseStream = this.GetWebResponse( request ).GetResponseStream(); + } + catch( WebException ) + { + throw; + } + catch( Exception exception2 ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + } + finally + { + this.is_busy = false; + } + return responseStream; + } + + //public void OpenReadAsync( Uri address ) + //{ + // this.OpenReadAsync( address, null ); + //} + + //public void OpenReadAsync( Uri address, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // WebRequest request = null; + // try + // { + // request = this.SetupRequest( (Uri)objArray[ 0 ] ); + // Stream result = this.GetWebResponse( request ).GetResponseStream(); + // this.OnOpenReadCompleted( new OpenReadCompletedEventArgs( result, null, false, objArray[ 1 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // if( request != null ) + // { + // request.Abort(); + // } + // this.OnOpenReadCompleted( new OpenReadCompletedEventArgs( null, null, true, objArray[ 1 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnOpenReadCompleted( new OpenReadCompletedEventArgs( null, exception, false, objArray[ 1 ] ) ); + // } + // }, parameter ); + // } + //} + + public Stream OpenWrite( string address ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.OpenWrite( this.CreateUri( address ) ); + } + + public Stream OpenWrite( Uri address ) + { + return this.OpenWrite( address, null ); + } + + public Stream OpenWrite( string address, string method ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.OpenWrite( this.CreateUri( address ), method ); + } + + public Stream OpenWrite( Uri address, string method ) + { + Stream requestStream; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + try + { + this.SetBusy(); + this.async = false; + requestStream = this.SetupRequest( address, method, true ).GetRequestStream(); + } + catch( WebException ) + { + throw; + } + catch( Exception exception2 ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + } + finally + { + this.is_busy = false; + } + return requestStream; + } + + //public void OpenWriteAsync( Uri address ) + //{ + // this.OpenWriteAsync( address, null ); + //} + + //public void OpenWriteAsync( Uri address, string method ) + //{ + // this.OpenWriteAsync( address, method, null ); + //} + + //public void OpenWriteAsync( Uri address, string method, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, method, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // WebRequest request = null; + // try + // { + // request = this.SetupRequest( (Uri)objArray[ 0 ], (string)objArray[ 1 ], true ); + // Stream result = request.GetRequestStream(); + // this.OnOpenWriteCompleted( new OpenWriteCompletedEventArgs( result, null, false, objArray[ 2 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // if( request != null ) + // { + // request.Abort(); + // } + // this.OnOpenWriteCompleted( new OpenWriteCompletedEventArgs( null, null, true, objArray[ 2 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnOpenWriteCompleted( new OpenWriteCompletedEventArgs( null, exception, false, objArray[ 2 ] ) ); + // } + // }, parameter ); + // } + //} + + private byte[] ReadAll( Stream stream, int length, object userToken ) + { + MemoryStream stream2 = null; + bool flag = length == -1; + int count = !flag ? length : 0x2000; + if( flag ) + { + stream2 = new MemoryStream(); + } + int num2 = 0; + int offset = 0; + byte[] buffer = new byte[ count ]; + while( ( num2 = stream.Read( buffer, offset, count ) ) != 0 ) + { + if( flag ) + { + stream2.Write( buffer, 0, num2 ); + } + else + { + offset += num2; + count -= num2; + } + } + if( flag ) + { + return stream2.ToArray(); + } + return buffer; + } + + private void SetBusy() + { + MyWebClient client = this; + lock( client ) + { + this.CheckBusy(); + this.is_busy = true; + } + } + + private WebRequest SetupRequest( Uri uri ) + { + WebRequest webRequest = this.GetWebRequest( uri ); + webRequest.ConnectionGroupName = ConnectionGroupName; + if( this.Proxy != null ) + { + webRequest.Proxy = this.Proxy; + } + webRequest.Credentials = this.credentials; + if( ( ( this.headers != null ) && ( this.headers.Count != 0 ) ) && ( webRequest is HttpWebRequest ) ) + { + HttpWebRequest request2 = (HttpWebRequest)webRequest; + string str = this.headers[ "Expect" ]; + string str2 = this.headers[ "Content-Type" ]; + string str3 = this.headers[ "Accept" ]; + string str4 = this.headers[ "Connection" ]; + string str5 = this.headers[ "User-Agent" ]; + string str6 = this.headers[ "Referer" ]; + this.headers.Remove( "Expect" ); + this.headers.Remove( "Content-Type" ); + this.headers.Remove( "Accept" ); + this.headers.Remove( "Connection" ); + this.headers.Remove( "Referer" ); + this.headers.Remove( "User-Agent" ); + webRequest.Headers = this.headers; + if( ( str != null ) && ( str.Length > 0 ) ) + { + request2.Expect = str; + } + if( ( str3 != null ) && ( str3.Length > 0 ) ) + { + request2.Accept = str3; + } + if( ( str2 != null ) && ( str2.Length > 0 ) ) + { + request2.ContentType = str2; + } + if( ( str4 != null ) && ( str4.Length > 0 ) ) + { + request2.Connection = str4; + } + if( ( str5 != null ) && ( str5.Length > 0 ) ) + { + request2.UserAgent = str5; + } + if( ( str6 != null ) && ( str6.Length > 0 ) ) + { + request2.Referer = str6; + } + } + this.responseHeaders = null; + return webRequest; + } + + private WebRequest SetupRequest( Uri uri, string method, bool is_upload ) + { + WebRequest request = this.SetupRequest( uri ); + request.Method = this.DetermineMethod( uri, method, is_upload ); + return request; + } + + public byte[] UploadData( string address, byte[] data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.UploadData( this.CreateUri( address ), data ); + } + + public byte[] UploadData( Uri address, byte[] data ) + { + return this.UploadData( address, null, data ); + } + + public byte[] UploadData( string address, string method, byte[] data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.UploadData( this.CreateUri( address ), method, data ); + } + + public byte[] UploadData( Uri address, string method, byte[] data ) + { + byte[] buffer; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + try + { + this.SetBusy(); + this.async = false; + buffer = this.UploadDataCore( address, method, data, null ); + } + catch( WebException ) + { + throw; + } + catch( Exception exception ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception ); + } + finally + { + this.is_busy = false; + } + return buffer; + } + + //public void UploadDataAsync( Uri address, byte[] data ) + //{ + // this.UploadDataAsync( address, null, data ); + //} + + //public void UploadDataAsync( Uri address, string method, byte[] data ) + //{ + // this.UploadDataAsync( address, method, data, null ); + //} + + //public void UploadDataAsync( Uri address, string method, byte[] data, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // if( data == null ) + // { + // throw new ArgumentNullException( "data" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, method, data, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // try + // { + // byte[] result = this.UploadDataCore( (Uri)objArray[ 0 ], (string)objArray[ 1 ], (byte[])objArray[ 2 ], objArray[ 3 ] ); + // this.OnUploadDataCompleted( new UploadDataCompletedEventArgs( result, null, false, objArray[ 3 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // this.OnUploadDataCompleted( new UploadDataCompletedEventArgs( null, null, true, objArray[ 3 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnUploadDataCompleted( new UploadDataCompletedEventArgs( null, exception, false, objArray[ 3 ] ) ); + // } + // }, parameter ); + // } + //} + + private byte[] UploadDataCore( Uri address, string method, byte[] data, object userToken ) + { + byte[] buffer; + WebRequest request = this.SetupRequest( address, method, true ); + try + { + int length = data.Length; + request.ContentLength = length; + using( Stream stream = request.GetRequestStream() ) + { + stream.Write( data, 0, length ); + } + WebResponse webResponse = this.GetWebResponse( request ); + Stream responseStream = webResponse.GetResponseStream(); + buffer = this.ReadAll( responseStream, (int)webResponse.ContentLength, userToken ); + } + catch( ThreadInterruptedException ) + { + if( request != null ) + { + request.Abort(); + } + throw; + } + return buffer; + } + + public byte[] UploadFile( string address, string fileName ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.UploadFile( this.CreateUri( address ), fileName ); + } + + public byte[] UploadFile( Uri address, string fileName ) + { + return this.UploadFile( address, null, fileName ); + } + + public byte[] UploadFile( string address, string method, string fileName ) + { + return this.UploadFile( this.CreateUri( address ), method, fileName ); + } + + public byte[] UploadFile( Uri address, string method, string fileName ) + { + byte[] buffer; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( fileName == null ) + { + throw new ArgumentNullException( "fileName" ); + } + try + { + this.SetBusy(); + this.async = false; + buffer = this.UploadFileCore( address, method, fileName, null ); + } + catch( WebException ) + { + throw; + } + catch( Exception exception2 ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + } + finally + { + this.is_busy = false; + } + return buffer; + } + + //public void UploadFileAsync( Uri address, string fileName ) + //{ + // this.UploadFileAsync( address, null, fileName ); + //} + + //public void UploadFileAsync( Uri address, string method, string fileName ) + //{ + // this.UploadFileAsync( address, method, fileName, null ); + //} + + //public void UploadFileAsync( Uri address, string method, string fileName, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // if( fileName == null ) + // { + // throw new ArgumentNullException( "fileName" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.SetBusy(); + // this.async = true; + // object[] parameter = new object[] { address, method, fileName, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // try + // { + // byte[] result = this.UploadFileCore( (Uri)objArray[ 0 ], (string)objArray[ 1 ], (string)objArray[ 2 ], objArray[ 3 ] ); + // this.OnUploadFileCompleted( new UploadFileCompletedEventArgs( result, null, false, objArray[ 3 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // this.OnUploadFileCompleted( new UploadFileCompletedEventArgs( null, null, true, objArray[ 3 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnUploadFileCompleted( new UploadFileCompletedEventArgs( null, exception, false, objArray[ 3 ] ) ); + // } + // }, parameter ); + // } + //} + + private byte[] UploadFileCore( Uri address, string method, string fileName, object userToken ) + { + string str = this.Headers[ "Content-Type" ]; + if( str != null ) + { + if( str.ToLower().StartsWith( "multipart/" ) ) + { + throw new WebException( "Content-Type cannot be set to a multipart type for this request." ); + } + } + else + { + str = "application/octet-stream"; + } + string str3 = "------------" + DateTime.Now.Ticks.ToString( "x" ); + this.Headers[ "Content-Type" ] = string.Format( "multipart/form-data; boundary={0}", str3 ); + Stream requestStream = null; + Stream stream2 = null; + byte[] buffer = null; + fileName = Path.GetFullPath( fileName ); + WebRequest request = null; + try + { + int num; + stream2 = System.IO.File.OpenRead( fileName ); + request = this.SetupRequest( address, method, true ); + requestStream = request.GetRequestStream(); + byte[] bytes = System.Text.Encoding.ASCII.GetBytes( "--" + str3 + "\r\n" ); + requestStream.Write( bytes, 0, bytes.Length ); + string s = string.Format( "Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\nContent-Type: {1}\r\n\r\n", Path.GetFileName( fileName ), str ); + byte[] buffer3 = System.Text.Encoding.UTF8.GetBytes( s ); + requestStream.Write( buffer3, 0, buffer3.Length ); + byte[] buffer4 = new byte[ 0x1000 ]; + while( ( num = stream2.Read( buffer4, 0, 0x1000 ) ) != 0 ) + { + requestStream.Write( buffer4, 0, num ); + } + requestStream.WriteByte( 13 ); + requestStream.WriteByte( 10 ); + requestStream.Write( bytes, 0, bytes.Length ); + requestStream.Close(); + requestStream = null; + WebResponse webResponse = this.GetWebResponse( request ); + Stream responseStream = webResponse.GetResponseStream(); + buffer = this.ReadAll( responseStream, (int)webResponse.ContentLength, userToken ); + } + catch( ThreadInterruptedException ) + { + if( request != null ) + { + request.Abort(); + } + throw; + } + finally + { + if( stream2 != null ) + { + stream2.Close(); + } + if( requestStream != null ) + { + requestStream.Close(); + } + } + return buffer; + } + + public string UploadString( string address, string data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + byte[] bytes = this.UploadData( address, this.encoding.GetBytes( data ) ); + return this.encoding.GetString( bytes ); + } + + public string UploadString( Uri address, string data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + byte[] bytes = this.UploadData( address, this.encoding.GetBytes( data ) ); + return this.encoding.GetString( bytes ); + } + + public string UploadString( string address, string method, string data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + byte[] bytes = this.UploadData( address, method, this.encoding.GetBytes( data ) ); + return this.encoding.GetString( bytes ); + } + + public string UploadString( Uri address, string method, string data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + byte[] bytes = this.UploadData( address, method, this.encoding.GetBytes( data ) ); + return this.encoding.GetString( bytes ); + } + + public void UploadStringAsync( Uri address, string data ) + { + this.UploadStringAsync( address, null, data ); + } + + public void UploadStringAsync( Uri address, string method, string data ) + { + this.UploadStringAsync( address, method, data, null ); + } + + public void UploadStringAsync( Uri address, string method, string data, object userToken ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + MyWebClient client = this; + lock( client ) + { + this.CheckBusy(); + this.async = true; + object[] parameter = new object[] { address, method, data, userToken }; + ThreadPool.QueueUserWorkItem( delegate ( object state ) + { + object[] objArray = (object[])state; + try + { + string result = this.UploadString( (Uri)objArray[ 0 ], (string)objArray[ 1 ], (string)objArray[ 2 ] ); + this.OnUploadStringCompleted( new MyUploadStringCompletedEventArgs( result, null, false, objArray[ 3 ] ) ); + } + catch( ThreadInterruptedException ) + { + this.OnUploadStringCompleted( new MyUploadStringCompletedEventArgs( null, null, true, objArray[ 3 ] ) ); + } + catch( Exception exception ) + { + this.OnUploadStringCompleted( new MyUploadStringCompletedEventArgs( null, exception, false, objArray[ 3 ] ) ); + } + }, parameter ); + } + } + + public byte[] UploadValues( string address, NameValueCollection data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.UploadValues( this.CreateUri( address ), data ); + } + + public byte[] UploadValues( Uri address, NameValueCollection data ) + { + return this.UploadValues( address, null, data ); + } + + public byte[] UploadValues( string address, string method, NameValueCollection data ) + { + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + return this.UploadValues( this.CreateUri( address ), method, data ); + } + + public byte[] UploadValues( Uri address, string method, NameValueCollection data ) + { + byte[] buffer; + if( address == null ) + { + throw new ArgumentNullException( "address" ); + } + if( data == null ) + { + throw new ArgumentNullException( "data" ); + } + try + { + this.SetBusy(); + this.async = false; + buffer = this.UploadValuesCore( address, method, data, null ); + } + catch( WebException ) + { + throw; + } + catch( Exception exception2 ) + { + throw new WebException( "An error occurred performing a WebClient request.", exception2 ); + } + finally + { + this.is_busy = false; + } + return buffer; + } + + //public void UploadValuesAsync( Uri address, NameValueCollection values ) + //{ + // this.UploadValuesAsync( address, null, values ); + //} + + //public void UploadValuesAsync( Uri address, string method, NameValueCollection values ) + //{ + // this.UploadValuesAsync( address, method, values, null ); + //} + + //public void UploadValuesAsync( Uri address, string method, NameValueCollection values, object userToken ) + //{ + // if( address == null ) + // { + // throw new ArgumentNullException( "address" ); + // } + // if( values == null ) + // { + // throw new ArgumentNullException( "values" ); + // } + // MyWebClient client = this; + // lock( client ) + // { + // this.CheckBusy(); + // this.async = true; + // object[] parameter = new object[] { address, method, values, userToken }; + // ThreadPool.QueueUserWorkItem( delegate ( object state ) + // { + // object[] objArray = (object[])state; + // try + // { + // byte[] result = this.UploadValuesCore( (Uri)objArray[ 0 ], (string)objArray[ 1 ], (NameValueCollection)objArray[ 2 ], objArray[ 3 ] ); + // this.OnUploadValuesCompleted( new UploadValuesCompletedEventArgs( result, null, false, objArray[ 3 ] ) ); + // } + // catch( ThreadInterruptedException ) + // { + // this.OnUploadValuesCompleted( new UploadValuesCompletedEventArgs( null, null, true, objArray[ 3 ] ) ); + // } + // catch( Exception exception ) + // { + // this.OnUploadValuesCompleted( new UploadValuesCompletedEventArgs( null, exception, false, objArray[ 3 ] ) ); + // } + // }, parameter ); + // } + //} + + private byte[] UploadValuesCore( Uri uri, string method, NameValueCollection data, object userToken ) + { + byte[] buffer3; + string strA = this.Headers[ "Content-Type" ]; + if( ( strA != null ) && ( string.Compare( strA, urlEncodedCType, true ) != 0 ) ) + { + throw new WebException( "Content-Type header cannot be changed from its default value for this request." ); + } + this.Headers[ "Content-Type" ] = urlEncodedCType; + WebRequest request = this.SetupRequest( uri, method, true ); + try + { + MemoryStream stream = new MemoryStream(); + IEnumerator enumerator = data.GetEnumerator(); + try + { + while( enumerator.MoveNext() ) + { + string current = (string)enumerator.Current; + byte[] bytes = System.Text.Encoding.UTF8.GetBytes( current ); + UrlEncodeAndWrite( stream, bytes ); + stream.WriteByte( 0x3d ); + bytes = System.Text.Encoding.UTF8.GetBytes( data[ current ] ); + UrlEncodeAndWrite( stream, bytes ); + stream.WriteByte( 0x26 ); + } + } + finally + { + IDisposable disposable = enumerator as IDisposable; + if( disposable != null ) + { + disposable.Dispose(); + } + } + int length = (int)stream.Length; + if( length > 0 ) + { + stream.SetLength( (long)( --length ) ); + } + byte[] buffer2 = stream.GetBuffer(); + request.ContentLength = length; + using( Stream stream2 = request.GetRequestStream() ) + { + stream2.Write( buffer2, 0, length ); + } + stream.Close(); + WebResponse webResponse = this.GetWebResponse( request ); + Stream responseStream = webResponse.GetResponseStream(); + buffer3 = this.ReadAll( responseStream, (int)webResponse.ContentLength, userToken ); + } + catch( ThreadInterruptedException ) + { + request.Abort(); + throw; + } + return buffer3; + } + + private string UrlEncode( string str ) + { + StringBuilder builder = new StringBuilder(); + int length = str.Length; + for( int i = 0 ; i < length ; i++ ) + { + char ch = str[ i ]; + if( ch == ' ' ) + { + builder.Append( '+' ); + } + else if( ( ( ( ( ch < '0' ) && ( ch != '-' ) ) && ( ch != '.' ) ) || ( ( ch < 'A' ) && ( ch > '9' ) ) ) || ( ( ( ( ch > 'Z' ) && ( ch < 'a' ) ) && ( ch != '_' ) ) || ( ch > 'z' ) ) ) + { + builder.Append( '%' ); + int index = ch >> 4; + builder.Append( (char)hexBytes[ index ] ); + index = ch & '\x000f'; + builder.Append( (char)hexBytes[ index ] ); + } + else + { + builder.Append( ch ); + } + } + return builder.ToString(); + } + + private static void UrlEncodeAndWrite( Stream stream, byte[] bytes ) + { + if( bytes != null ) + { + int length = bytes.Length; + if( length != 0 ) + { + for( int i = 0 ; i < length ; i++ ) + { + char ch = (char)bytes[ i ]; + if( ch == ' ' ) + { + stream.WriteByte( 0x2b ); + } + else if( ( ( ( ( ch < '0' ) && ( ch != '-' ) ) && ( ch != '.' ) ) || ( ( ch < 'A' ) && ( ch > '9' ) ) ) || ( ( ( ( ch > 'Z' ) && ( ch < 'a' ) ) && ( ch != '_' ) ) || ( ch > 'z' ) ) ) + { + stream.WriteByte( 0x25 ); + int index = ch >> 4; + stream.WriteByte( hexBytes[ index ] ); + index = ch & '\x000f'; + stream.WriteByte( hexBytes[ index ] ); + } + else + { + stream.WriteByte( (byte)ch ); + } + } + } + } + } + + public string BaseAddress + { + get + { + if( ( this.baseString == null ) && ( this.baseAddress == null ) ) + { + return string.Empty; + } + this.baseString = this.baseAddress.ToString(); + return this.baseString; + } + set + { + if( ( value == null ) || ( value.Length == 0 ) ) + { + this.baseAddress = null; + } + else + { + this.baseAddress = new Uri( value ); + } + } + } + + public RequestCachePolicy CachePolicy + { + get + { + throw GetMustImplement(); + } + set + { + throw GetMustImplement(); + } + } + + public ICredentials Credentials + { + get + { + return this.credentials; + } + set + { + this.credentials = value; + } + } + + public System.Text.Encoding Encoding + { + get + { + return this.encoding; + } + set + { + if( value == null ) + { + throw new ArgumentNullException( "Encoding" ); + } + this.encoding = value; + } + } + + public WebHeaderCollection Headers + { + get + { + if( this.headers == null ) + { + this.headers = new WebHeaderCollection(); + } + return this.headers; + } + set + { + this.headers = value; + } + } + + public bool IsBusy + { + get + { + return this.is_busy; + } + } + + public IWebProxy Proxy + { + get + { + return this.proxy; + } + set + { + this.proxy = value; + } + } + + public NameValueCollection QueryString + { + get + { + if( this.queryString == null ) + { + this.queryString = new NameValueCollection(); + } + return this.queryString; + } + set + { + this.queryString = value; + } + } + + public WebHeaderCollection ResponseHeaders + { + get + { + return this.responseHeaders; + } + } + + public bool UseDefaultCredentials + { + get + { + throw GetMustImplement(); + } + set + { + throw GetMustImplement(); + } + } + } + +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/Security.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/Security.cs new file mode 100644 index 00000000..8e70ee0b --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/Security.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public static class Security + { + public static RemoteCertificateValidationCallback AlwaysAllowByHosts( params string[] hosts ) + { + var lookup = new HashSet( hosts, StringComparer.OrdinalIgnoreCase ); + + return ( sender, certificate, chain, sslPolicyErrors ) => + { + var request = sender as HttpWebRequest; + if( request != null ) + { + return lookup.Contains( request.Address.Host ); + } + return false; + }; + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/UnityWebClient.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/UnityWebClient.cs new file mode 100644 index 00000000..fa6beced --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/UnityWebClient.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using Harmony; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Shim; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class UnityWebClient : MyWebClient + { + private KnownHttpEndpoint _httpEndpoint; + + public UnityWebClient( KnownHttpEndpoint endpoint ) + { + _httpEndpoint = endpoint; + Encoding = Encoding.UTF8; + DownloadStringCompleted += UnityWebClient_DownloadStringCompleted; + UploadStringCompleted += UnityWebClient_UploadStringCompleted; + } + + private void UnityWebClient_UploadStringCompleted( object sender, MyUploadStringCompletedEventArgs ev ) + { + var handle = ev.UserState as DownloadResult; + + // obtain result, error, etc. + string text = null; + string error = null; + + try + { + if( ev.Error == null ) + { + text = ev.Result ?? string.Empty; + } + else + { + error = ev.Error.ToString(); + } + } + catch( Exception e ) + { + error = e.ToString(); + } + + handle.SetCompleted( text, error ); + } + + private void UnityWebClient_DownloadStringCompleted( object sender, MyDownloadStringCompletedEventArgs ev ) + { + var handle = ev.UserState as DownloadResult; + + // obtain result, error, etc. + string text = null; + string error = null; + + try + { + if( ev.Error == null ) + { + text = ev.Result ?? string.Empty; + } + else + { + error = ev.Error.ToString(); + } + } + catch( Exception e ) + { + error = e.ToString(); + } + + handle.SetCompleted( text, error ); + } + + protected override WebRequest GetWebRequest( Uri address ) + { + var request = base.GetWebRequest( address ); + var httpRequest = request as HttpWebRequest; + if( httpRequest != null ) + { + var cookies = _httpEndpoint.ReadCookies(); + httpRequest.CookieContainer = cookies; + } + return request; + } + + protected override WebResponse GetWebResponse( WebRequest request, IAsyncResult result ) + { + WebResponse response = base.GetWebResponse( request, result ); + WriteCookies( response ); + return response; + } + + protected override WebResponse GetWebResponse( WebRequest request ) + { + WebResponse response = base.GetWebResponse( request ); + WriteCookies( response ); + return response; + } + + private void WriteCookies( WebResponse r ) + { + var response = r as HttpWebResponse; + if( response != null ) + { + _httpEndpoint.WriteCookies( response ); + } + } + + public DownloadResult GetDownloadResult( Uri address ) + { + var handle = new DownloadResult(); + DownloadStringAsync( address, handle ); + return handle; + } + + public DownloadResult GetDownloadResult( Uri address, string request ) + { + var handle = new DownloadResult(); + UploadStringAsync( address, "POST", request, handle ); + return handle; + } + } + + public class DownloadResult : CustomYieldInstructionShim + { + private bool _isCompleted = false; + + public void SetCompleted( string result, string error ) + { + _isCompleted = true; + Result = result; + Error = error; + } + + public override bool keepWaiting => !_isCompleted; + + public string Result { get; set; } + + public string Error { get; set; } + + public bool IsCompleted => _isCompleted; + + public bool Succeeded => Error == null; + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/WatsonTranslateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/WatsonTranslateEndpoint.cs new file mode 100644 index 00000000..e9655b18 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/WatsonTranslateEndpoint.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using SimpleJSON; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class WatsonTranslateEndpoint : KnownWwwEndpoint + { + private static readonly string HttpsServicePointTemplateUrl = Settings.WatsonAPIUrl.TrimEnd( '/' ) + "/v2/translate?model_id={0}-{1}&text={2}"; + + public WatsonTranslateEndpoint() + { + //ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( new Uri( Settings.WatsonAPIUrl ).Host ); + } + + public override void ApplyHeaders( Dictionary headers ) + { + headers[ "User-Agent" ] = Settings.GetUserAgent( "curl/7.55.1" ); + headers[ "Accept" ] = "application/json"; + headers[ "Accept-Charset" ] = "UTF-8"; + headers[ "Authorization" ] = "Basic " + System.Convert.ToBase64String( System.Text.Encoding.ASCII.GetBytes( Settings.WatsonAPIUsername + ":" + Settings.WatsonAPIPassword ) ); + } + + //public override void ApplyHeaders( WebHeaderCollection headers ) + //{ + // headers[ HttpRequestHeader.UserAgent ] = "curl/7.55.1"; + // headers[ HttpRequestHeader.Accept ] = "application/json"; + // headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8"; + // headers[ HttpRequestHeader.Authorization ] = "Basic " + System.Convert.ToBase64String( System.Text.Encoding.ASCII.GetBytes( Settings.WatsonAPIUsername + ":" + Settings.WatsonAPIPassword ) ); + //} + + public override bool TryExtractTranslated( string result, out string translated ) + { + try + { + var obj = JSON.Parse( result ); + var lineBuilder = new StringBuilder( result.Length ); + + foreach( JSONNode entry in obj.AsObject[ "translations" ].AsArray ) + { + var token = entry.AsObject[ "translation" ].ToString(); + token = token.Substring( 1, token.Length - 2 ).UnescapeJson(); + + if( !lineBuilder.EndsWithWhitespaceOrNewline() ) lineBuilder.Append( "\n" ); + + lineBuilder.Append( token ); + } + translated = lineBuilder.ToString(); + + var success = !string.IsNullOrEmpty( translated ); + return success; + } + catch( Exception ) + { + translated = null; + return false; + } + } + + public override string GetServiceUrl( string untranslatedText, string from, string to ) + { + return string.Format( HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL( untranslatedText ) ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/WebClientReference.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/WebClientReference.cs deleted file mode 100644 index d91ecc56..00000000 --- a/src/XUnity.AutoTranslator.Plugin.Core/Web/WebClientReference.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; - -namespace XUnity.AutoTranslator.Plugin.Core.Web -{ - public class WebClientReference - { - public WebClientReference( WebClient client ) - { - Client = client; - LastTimestamp = DateTime.UtcNow; - } - - public WebClient Client { get; } - - public DateTime LastTimestamp { get; set; } - } -} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/Web/YandexTranslateEndpoint.cs b/src/XUnity.AutoTranslator.Plugin.Core/Web/YandexTranslateEndpoint.cs new file mode 100644 index 00000000..0a277b02 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/Web/YandexTranslateEndpoint.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using SimpleJSON; +using UnityEngine; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; +using XUnity.AutoTranslator.Plugin.Core.Extensions; + +namespace XUnity.AutoTranslator.Plugin.Core.Web +{ + public class YandexTranslateEndpoint : KnownHttpEndpoint + { + private static readonly string HttpsServicePointTemplateUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key={3}&text={2}&lang={0}-{1}&format=plain"; + public YandexTranslateEndpoint() + { + ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translate.yandex.net" ); + } + + public override void ApplyHeaders( WebHeaderCollection headers ) + { + headers[ HttpRequestHeader.UserAgent ] = Settings.GetUserAgent( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.55" ); + headers[ HttpRequestHeader.Accept ] = "*/*"; + headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8"; + } + + public override bool TryExtractTranslated( string result, out string translated ) + { + try + { + + var obj = JSON.Parse( result ); + var lineBuilder = new StringBuilder( result.Length ); + + var code = obj.AsObject[ "code" ].ToString(); + + if( code == "200" ) + { + var token = obj.AsObject[ "text" ].ToString(); + token = token.Substring( 2, token.Length - 4 ).UnescapeJson(); + if( String.IsNullOrEmpty( token ) ) + { + translated = null; + return false; + } + + if( !lineBuilder.EndsWithWhitespaceOrNewline() ) lineBuilder.Append( "\n" ); + lineBuilder.Append( token ); + + translated = lineBuilder.ToString(); + + var success = !string.IsNullOrEmpty( translated ); + return success; + } + else + { + translated = null; + return false; + } + } + catch( Exception ) + { + translated = null; + return false; + } + } + + public override string GetServiceUrl( string untranslatedText, string from, string to ) + { + return string.Format( HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL( untranslatedText ), Settings.YandexAPIKey ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/WhitespaceHandlingStrategy.cs b/src/XUnity.AutoTranslator.Plugin.Core/WhitespaceHandlingStrategy.cs new file mode 100644 index 00000000..608c04e5 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.Core/WhitespaceHandlingStrategy.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace XUnity.AutoTranslator.Plugin.Core +{ + public enum WhitespaceHandlingStrategy + { + AllOccurrences, + TrimPerNewline + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj b/src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj index 92e7166a..9b3b34c1 100644 --- a/src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj +++ b/src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj @@ -1,25 +1,46 @@ - + - - net35 - 2.5.0.0 - 2.5.0.0 - 2.5.0 - + + net35 + 2.14.0 + - - - ..\..\libs\0Harmony.dll - - - ..\..\libs\ExIni.dll - - - ..\..\libs\UnityEngine.dll - - - ..\..\libs\UnityEngine.UI.dll - - + + + + + + + ..\..\libs\0Harmony.dll + + + ..\..\libs\ExIni.dll + + + ..\..\libs\UnityEngine.dll + + + ..\..\libs\UnityEngine.UI.dll + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + diff --git a/src/XUnity.AutoTranslator.Plugin.IPA/XUnity.AutoTranslator.Plugin.IPA.csproj b/src/XUnity.AutoTranslator.Plugin.IPA/XUnity.AutoTranslator.Plugin.IPA.csproj index 2d8b450c..85cf99cd 100644 --- a/src/XUnity.AutoTranslator.Plugin.IPA/XUnity.AutoTranslator.Plugin.IPA.csproj +++ b/src/XUnity.AutoTranslator.Plugin.IPA/XUnity.AutoTranslator.Plugin.IPA.csproj @@ -1,10 +1,8 @@ - + net35 - 2.5.0.0 - 2.5.0.0 - 2.5.0 + 2.14.0 @@ -30,7 +28,7 @@ - + diff --git a/src/XUnity.AutoTranslator.Plugin.UnityInjector/AutoTranslatorPlugin.cs b/src/XUnity.AutoTranslator.Plugin.UnityInjector/AutoTranslatorPlugin.cs new file mode 100644 index 00000000..e21a4d15 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.UnityInjector/AutoTranslatorPlugin.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ExIni; +using UnityInjector; +using UnityInjector.Attributes; +using XUnity.AutoTranslator.Plugin.Core; +using XUnity.AutoTranslator.Plugin.Core.Configuration; +using XUnity.AutoTranslator.Plugin.Core.Constants; + +namespace XUnity.AutoTranslator.Plugin.UnityInjector +{ + [PluginName( PluginData.Name ), PluginVersion( PluginData.Version )] + public class AutoTranslatorPlugin : PluginBase, IConfiguration + { + IniFile IConfiguration.ReloadConfig() + { + return ReloadConfig(); + } + + void IConfiguration.SaveConfig() + { + SaveConfig(); + } + + public void Awake() + { + PluginLoader.LoadWithConfig( this ); + } + } +} diff --git a/src/XUnity.AutoTranslator.Plugin.UnityInjector/XUnity.AutoTranslator.Plugin.UnityInjector.csproj b/src/XUnity.AutoTranslator.Plugin.UnityInjector/XUnity.AutoTranslator.Plugin.UnityInjector.csproj new file mode 100644 index 00000000..bf1cb697 --- /dev/null +++ b/src/XUnity.AutoTranslator.Plugin.UnityInjector/XUnity.AutoTranslator.Plugin.UnityInjector.csproj @@ -0,0 +1,34 @@ + + + + net35 + 2.14.0 + + + + + + + + + ..\..\libs\ExIni.dll + + + ..\..\libs\UnityEngine.dll + + + ..\..\libs\UnityInjector.dll + + + + + + + + + + + + + + diff --git a/src/XUnity.AutoTranslator.Setup/Program.cs b/src/XUnity.AutoTranslator.Setup/Program.cs index 134ca630..52f6e3e3 100644 --- a/src/XUnity.AutoTranslator.Setup/Program.cs +++ b/src/XUnity.AutoTranslator.Setup/Program.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using IWshRuntimeLibrary; +using XUnity.AutoTranslator.Setup.Properties; namespace XUnity.AutoTranslator.Setup { class Program { + [STAThread] static void Main( string[] args ) { var gamePath = Environment.CurrentDirectory; @@ -27,33 +28,27 @@ static void Main( string[] args ) } var reiPath = Path.Combine( gamePath, "ReiPatcher" ); - var reiInfo = new DirectoryInfo( reiPath ); - if( !reiInfo.Exists ) - { - Console.WriteLine( "ReiPatcher directory missing!" ); - Console.WriteLine( "Press any key to exit..." ); - return; - } + var patchesPath = Path.Combine( reiPath, "Patches" ); + + // lets add any missing files + AddFile( Path.Combine( reiPath, "ExIni.dll" ), Resources.ExIni ); + AddFile( Path.Combine( reiPath, "Mono.Cecil.dll" ), Resources.Mono_Cecil ); + AddFile( Path.Combine( reiPath, "Mono.Cecil.Inject.dll" ), Resources.Mono_Cecil_Inject ); + AddFile( Path.Combine( reiPath, "Mono.Cecil.Mdb.dll" ), Resources.Mono_Cecil_Mdb ); + AddFile( Path.Combine( reiPath, "Mono.Cecil.Pdb.dll" ), Resources.Mono_Cecil_Pdb ); + AddFile( Path.Combine( reiPath, "Mono.Cecil.Rocks.dll" ), Resources.Mono_Cecil_Rocks ); + AddFile( Path.Combine( reiPath, "ReiPatcher.exe" ), Resources.ReiPatcher ); + AddFile( Path.Combine( patchesPath, "XUnity.AutoTranslator.Patcher.dll" ), Resources.XUnity_AutoTranslator_Patcher, true ); + foreach( var launcher in launchers ) { - var setupPath = Path.Combine( gamePath, "AutoTranslatorSetupFiles" ); - var setupInfo = new DirectoryInfo( setupPath ); - if( setupInfo.Exists ) - { - var setupFiles = setupInfo.GetFiles( "*.dll", SearchOption.TopDirectoryOnly ).Concat( setupInfo.GetFiles( "*.exe", SearchOption.TopDirectoryOnly ) ); - foreach( var setupFile in setupFiles ) - { - var copyToPath = Path.Combine( gamePath, launcher.Data.Name, "Managed", setupFile.Name ); - var copyToFile = new FileInfo( copyToPath ); - setupFile.CopyTo( copyToPath, true ); - Console.WriteLine( "Copied " + setupFile.Name + " to " + launcher.Data.FullName ); - } - } - else - { - Console.WriteLine( "AutoTranslatorSetupFiles directory missing. Skipping copying files to managed directory..." ); - } + var managedDir = Path.Combine( gamePath, launcher.Data.Name, "Managed" ); + AddFile( Path.Combine( managedDir, "0Harmony.dll" ), Resources._0Harmony ); + AddFile( Path.Combine( managedDir, "ExIni.dll" ), Resources.ExIni ); + AddFile( Path.Combine( managedDir, "ReiPatcher.exe" ), Resources.ReiPatcher ); // needed because file is modified by attribute in ReiPatcher... QQ + AddFile( Path.Combine( managedDir, "Jurassic.dll" ), Resources.Jurassic ); + AddFile( Path.Combine( managedDir, "XUnity.AutoTranslator.Plugin.Core.dll" ), Resources.XUnity_AutoTranslator_Plugin_Core, true ); // create an .ini file for each launcher, if it does not already exist var iniInfo = new FileInfo( Path.Combine( reiPath, Path.GetFileNameWithoutExtension( launcher.Executable.Name ) + ".ini" ) ); @@ -105,16 +100,45 @@ static void Main( string[] args ) Console.ReadKey(); } + public static void AddFile( string fileName, byte[] bytes, bool overwrite = false ) + { + var fi = new FileInfo( fileName ); + if( !fi.Exists ) + { + if( !fi.Directory.Exists ) + { + Directory.CreateDirectory( fi.Directory.FullName ); + Console.WriteLine( "Created directory: " + fi.Directory.FullName ); + } + System.IO.File.WriteAllBytes( fi.FullName, bytes ); + Console.WriteLine( "Created file: " + fi.FullName ); + } + else if( overwrite ) + { + System.IO.File.WriteAllBytes( fi.FullName, bytes ); + Console.WriteLine( "Updated file: " + fi.FullName ); + } + } + public static void CreateShortcut( string shortcutName, string shortcutPath, string targetFileLocation ) { string shortcutLocation = Path.Combine( shortcutPath, shortcutName ); - WshShell shell = new WshShell(); - IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut( shortcutLocation ); - shortcut.WorkingDirectory = Path.GetDirectoryName( targetFileLocation ); - shortcut.TargetPath = targetFileLocation; - shortcut.Arguments = "-c " + Path.GetFileNameWithoutExtension( shortcutName ) + ".ini"; - shortcut.Save(); + // Create empty .lnk file + File.WriteAllBytes( shortcutName, new byte[ 0 ] ); + + // Create a ShellLinkObject that references the .lnk file + Shell32.Shell shl = new Shell32.Shell(); + Shell32.Folder dir = shl.NameSpace( Path.GetDirectoryName( shortcutLocation ) ); + Shell32.FolderItem itm = dir.Items().Item( shortcutName ); + Shell32.ShellLinkObject lnk = (Shell32.ShellLinkObject)itm.GetLink; + + // Set the .lnk file properties + lnk.Path = targetFileLocation; + lnk.Arguments = "-c \"" + Path.GetFileNameWithoutExtension( shortcutName ) + ".ini\""; + lnk.WorkingDirectory = Path.GetDirectoryName( targetFileLocation ); + + lnk.Save( shortcutName ); } } } diff --git a/src/XUnity.AutoTranslator.Setup/Properties/Resources.Designer.cs b/src/XUnity.AutoTranslator.Setup/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8d821596 --- /dev/null +++ b/src/XUnity.AutoTranslator.Setup/Properties/Resources.Designer.cs @@ -0,0 +1,173 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XUnity.AutoTranslator.Setup.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("XUnity.AutoTranslator.Setup.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] _0Harmony { + get { + object obj = ResourceManager.GetObject("_0Harmony", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ExIni { + get { + object obj = ResourceManager.GetObject("ExIni", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Jurassic { + get { + object obj = ResourceManager.GetObject("Jurassic", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Mono_Cecil { + get { + object obj = ResourceManager.GetObject("Mono_Cecil", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Mono_Cecil_Inject { + get { + object obj = ResourceManager.GetObject("Mono_Cecil_Inject", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Mono_Cecil_Mdb { + get { + object obj = ResourceManager.GetObject("Mono_Cecil_Mdb", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Mono_Cecil_Pdb { + get { + object obj = ResourceManager.GetObject("Mono_Cecil_Pdb", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Mono_Cecil_Rocks { + get { + object obj = ResourceManager.GetObject("Mono_Cecil_Rocks", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ReiPatcher { + get { + object obj = ResourceManager.GetObject("ReiPatcher", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] XUnity_AutoTranslator_Patcher { + get { + object obj = ResourceManager.GetObject("XUnity_AutoTranslator_Patcher", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] XUnity_AutoTranslator_Plugin_Core { + get { + object obj = ResourceManager.GetObject("XUnity_AutoTranslator_Plugin_Core", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/src/XUnity.AutoTranslator.Setup/Properties/Resources.resx b/src/XUnity.AutoTranslator.Setup/Properties/Resources.resx new file mode 100644 index 00000000..4d284b3d --- /dev/null +++ b/src/XUnity.AutoTranslator.Setup/Properties/Resources.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\..\..\libs\ExIni.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\XUnity.AutoTranslator.Plugin.Core\bin\Release\net35\Jurassic.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\Mono.Cecil.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\Mono.Cecil.Inject.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\Mono.Cecil.Mdb.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\Mono.Cecil.Pdb.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\Mono.Cecil.Rocks.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\ReiPatcher.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\XUnity.AutoTranslator.Patcher\bin\Release\net35\XUnity.AutoTranslator.Patcher.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\XUnity.AutoTranslator.Plugin.Core\bin\Release\net35\XUnity.AutoTranslator.Plugin.Core.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\..\libs\0Harmony.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/XUnity.AutoTranslator.Setup/XUnity.AutoTranslator.Setup.csproj b/src/XUnity.AutoTranslator.Setup/XUnity.AutoTranslator.Setup.csproj index d4d2e5e9..c5ab7d69 100644 --- a/src/XUnity.AutoTranslator.Setup/XUnity.AutoTranslator.Setup.csproj +++ b/src/XUnity.AutoTranslator.Setup/XUnity.AutoTranslator.Setup.csproj @@ -1,25 +1,52 @@ - + - - Exe - net40 - + + Exe + net40 + SetupReiPatcherAndAutoTranslator + 2.14.0 + - - - f935dc20-1cf0-11d0-adb9-00c04fd58a0b - 1 - 0 - tlbimp - 0 - false - false - true - - + + + 50a7e9b0-70ef-11d1-b75a-00a0c90564fe + 1 + 0 + tlbimp + 0 + false + true + false + + - - - + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + +