Skip to content

Commit e7e2f3d

Browse files
author
Ramin Ahmadi
committed
Add document translation sample
Add document translation sample
1 parent 84f242e commit e7e2f3d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+39421
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Dependency directories
10+
node_modules/
11+
jspm_packages/
12+
13+
# TypeScript cache
14+
*.tsbuildinfo
15+
16+
# Optional npm cache directory
17+
.npm
18+
19+
# Optional eslint cache
20+
.eslintcache
21+
22+
# Output of 'npm pack'
23+
*.tgz
24+
25+
# Yarn Integrity file
26+
.yarn-integrity
27+
28+
# dotenv environment variables file
29+
.env
30+
.env.test
31+
.env.local
32+
33+
# SPFx build output
34+
SPFx/dist/
35+
SPFx/lib/
36+
SPFx/temp/
37+
SPFx/coverage/
38+
SPFx/release/
39+
SPFx/sharepoint/
40+
41+
# Azure Function build output
42+
AzureFunction/**/bin/
43+
AzureFunction/**/obj/
44+
AzureFunction/**/.vs/
45+
AzureFunction/**/*.user
46+
AzureFunction/**/*.suo
47+
AzureFunction/**/.vscode/
48+
AzureFunction/**/local.settings.json
49+
50+
# OS generated files
51+
.DS_Store
52+
.DS_Store?
53+
._*
54+
.Spotlight-V100
55+
.Trashes
56+
ehthumbs.db
57+
Thumbs.db
58+
59+
# IDE
60+
.vscode/
61+
.idea/
62+
*.swp
63+
*.swo
64+
*~
65+
66+
# Azure Storage Emulator
67+
__blobstorage__/
68+
__queuestorage__/
69+
__azurite_db*__.json
138 KB
Loading
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
6+
<OutputType>Exe</OutputType>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<UserSecretsId>8fd684cc-26c3-59e2-940e-25c29bf8bbf1</UserSecretsId>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<Content Include="host.json" />
13+
<Content Include="local.settings.json">
14+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
15+
</Content>
16+
</ItemGroup>
17+
<ItemGroup>
18+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
19+
</ItemGroup>
20+
<ItemGroup>
21+
<PackageReference Include="Azure.Data.Tables" Version="12.11.0" />
22+
<PackageReference Include="Azure.Identity" Version="1.13.2" />
23+
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.18.1" />
24+
<PackageReference Include="Azure.Storage.Blobs" Version="12.26.0-beta.1" />
25+
<PackageReference Include="FluentValidation" Version="12.0.0" />
26+
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.23.0" />
27+
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.0.0" />
28+
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="2.0.0" />
29+
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.0.1" />
30+
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.23.0" />
31+
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs" Version="6.7.0" />
32+
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.5" />
33+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.0-preview.7.25380.108" />
34+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
35+
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
36+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
37+
<PackageReference Include="PnP.Core" Version="1.15.122-nightly" />
38+
<PackageReference Include="PnP.Core.Auth" Version="1.15.122-nightly" />
39+
<PackageReference Include="Polly" Version="8.6.2" />
40+
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
41+
</ItemGroup>
42+
<ItemGroup>
43+
<None Update="host.json">
44+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
45+
</None>
46+
</ItemGroup>
47+
<ItemGroup>
48+
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
49+
</ItemGroup>
50+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.13.35825.156 d17.13
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentTranslationApp", "DocumentTranslationApp.csproj", "{30B344B5-EB42-B184-1746-0AC0D4B9EB7D}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{30B344B5-EB42-B184-1746-0AC0D4B9EB7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{30B344B5-EB42-B184-1746-0AC0D4B9EB7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{30B344B5-EB42-B184-1746-0AC0D4B9EB7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{30B344B5-EB42-B184-1746-0AC0D4B9EB7D}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {D5EAEA8B-E51D-4ADD-B867-EB32C21D5380}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace DocumentTranslationApp.Models;
2+
3+
public class SpfxTranslationRequest
4+
{
5+
public required string SiteUrl { get; set; }
6+
public required List<DocumentInfo> Documents { get; set; }
7+
public required TranslationOptions Options { get; set; }
8+
public RequestContext? Context { get; set; }
9+
}
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
namespace DocumentTranslationApp.Models;
2+
3+
public enum JobStatus
4+
{
5+
Pending,
6+
Running,
7+
Processing,
8+
Completed,
9+
Failed,
10+
Cancelled,
11+
}
12+
13+
public class TranslationRequest
14+
{
15+
public required string SiteUrl { get; set; }
16+
public required List<DocumentInfo> Documents { get; set; }
17+
public required TranslationOptions Options { get; set; }
18+
public RequestContext? Context { get; set; }
19+
public string? UserAccessToken { get; set; } // Token from SPFx for On-Behalf-Of flow
20+
}
21+
22+
public class DocumentInfo
23+
{
24+
public required string Id { get; set; }
25+
public required string Name { get; set; }
26+
public required string ServerRelativeUrl { get; set; }
27+
public long Size { get; set; }
28+
public required string FileType { get; set; }
29+
public bool IsSupported { get; set; }
30+
public string? ErrorMessage { get; set; }
31+
}
32+
33+
public class TranslationOptions
34+
{
35+
public string? SourceLanguage { get; set; } // Optional for auto-detect
36+
public required List<string> TargetLanguages { get; set; }
37+
}
38+
39+
public class RequestContext
40+
{
41+
public required string UserId { get; set; }
42+
public required string WebId { get; set; }
43+
public required string TenantId { get; set; } // Required for On-Behalf-Of flow
44+
public required string ListId { get; set; }
45+
}
46+
47+
public class TranslationResult
48+
{
49+
public bool Success { get; set; }
50+
public required string JobId { get; set; }
51+
public required string Message { get; set; }
52+
public int EstimatedDocuments { get; set; }
53+
public List<string>? Errors { get; set; }
54+
}
55+
56+
public class TranslatedDocument
57+
{
58+
public required string OriginalName { get; set; }
59+
public required string TargetLanguage { get; set; }
60+
public required string TranslatedName { get; set; }
61+
public required string ServerRelativeUrl { get; set; }
62+
public int CharacterCount { get; set; }
63+
}
64+
65+
public class FailedDocument
66+
{
67+
public required string Name { get; set; }
68+
public required string TargetLanguage { get; set; }
69+
public required string Error { get; set; }
70+
}
71+
72+
public class TranslationJobStatus
73+
{
74+
public required string JobId { get; set; }
75+
public JobStatus Status { get; set; }
76+
public int Progress { get; set; }
77+
public string? Message { get; set; }
78+
public List<TranslatedDocument> CompletedDocuments { get; set; } = new();
79+
public List<FailedDocument> FailedDocuments { get; set; } = new();
80+
public int TotalDocuments { get; set; }
81+
public long TotalCharacterCharged { get; set; }
82+
public DateTime CreatedAt { get; set; }
83+
public DateTime? CompletedAt { get; set; }
84+
}
85+
86+
public class ProcessingJob
87+
{
88+
public required string JobId { get; set; }
89+
public required string SiteUrl { get; set; }
90+
public required List<DocumentInfo> Documents { get; set; }
91+
public required TranslationOptions Options { get; set; }
92+
public RequestContext? Context { get; set; }
93+
public JobStatus Status { get; set; }
94+
public int Progress { get; set; }
95+
public string? Message { get; set; }
96+
public List<TranslatedDocument> CompletedDocuments { get; set; } = new();
97+
public List<FailedDocument> FailedDocuments { get; set; } = new();
98+
public int TotalDocuments { get; set; }
99+
public long TotalCharacterCharged { get; set; }
100+
public DateTime CreatedAt { get; set; }
101+
public DateTime? CompletedAt { get; set; }
102+
public string? ErrorMessage { get; set; }
103+
public string? UserAccessToken { get; set; } // Store user token for On-Behalf-Of flow
104+
public string? AzureTranslationJobId { get; set; } // Azure Document Translation API job ID
105+
public int RetryCount { get; set; } = 0;
106+
public int MaxRetries { get; set; } = 3;
107+
}
108+
109+
public class DocumentContent
110+
{
111+
public required string FileName { get; set; }
112+
public required byte[] Bytes { get; set; }
113+
public required string FileType { get; set; }
114+
public required string ContentType { get; set; }
115+
}
116+
117+
// Azure Document Translation API Models
118+
public class AzureTranslationBatchRequest
119+
{
120+
public required List<AzureTranslationInput> Inputs { get; set; }
121+
}
122+
123+
public class AzureTranslationInput
124+
{
125+
public required AzureTranslationSource Source { get; set; }
126+
public required List<AzureTranslationTarget> Targets { get; set; }
127+
}
128+
129+
public class AzureTranslationSource
130+
{
131+
public required string SourceUrl { get; set; }
132+
public string? Language { get; set; } // Optional for auto-detect
133+
public string StorageSource { get; set; } = "AzureBlob";
134+
}
135+
136+
public class AzureTranslationTarget
137+
{
138+
public required string TargetUrl { get; set; }
139+
public required string Language { get; set; }
140+
public string StorageSource { get; set; } = "AzureBlob";
141+
}
142+
143+
public class AzureTranslationBatchResponse
144+
{
145+
public required string Id { get; set; }
146+
public required DateTime CreatedDateTimeUtc { get; set; }
147+
public required DateTime LastActionDateTimeUtc { get; set; }
148+
public required string Status { get; set; }
149+
public required AzureTranslationSummary Summary { get; set; }
150+
}
151+
152+
public class AzureTranslationSummary
153+
{
154+
public int Total { get; set; }
155+
public int Failed { get; set; }
156+
public int Success { get; set; }
157+
public int InProgress { get; set; }
158+
public int NotYetStarted { get; set; }
159+
public int Cancelled { get; set; }
160+
public long TotalCharacterCharged { get; set; }
161+
}
162+
163+
public class AzureBlobItem
164+
{
165+
public required string Name { get; set; }
166+
public required MemoryStream Stream { get; set; }
167+
public required string Url { get; set; }
168+
}
169+
170+
public class DocumentTranslationJobStatus
171+
{
172+
public string JobId { get; set; } = string.Empty;
173+
public string Status { get; set; } = string.Empty;
174+
public DateTime CreatedDateTime { get; set; }
175+
public DateTime LastUpdatedDateTime { get; set; }
176+
public string? ExpirationDateTime { get; set; }
177+
public List<DocumentTranslationResult> Results { get; set; } = new();
178+
public List<DocumentTranslationError> Errors { get; set; } = new();
179+
180+
public long TotalCharacterCharged { get; set; }
181+
182+
// Task summary information
183+
public int TasksCompleted { get; set; }
184+
public int TasksFailed { get; set; }
185+
public int TasksInProgress { get; set; }
186+
public int TasksTotal { get; set; }
187+
188+
// Top-level error information (for ValidationFailed status)
189+
public string? ErrorCode { get; set; }
190+
public string? ErrorMessage { get; set; }
191+
public string? ErrorTarget { get; set; }
192+
193+
}
194+
195+
public class DocumentTranslationResult
196+
{
197+
public required string DocumentId { get; set; }
198+
public required string Status { get; set; }
199+
public string? Path { get; set; }
200+
public string? TranslatedDocumentLocation { get; set; }
201+
}
202+
203+
public class AppInfo
204+
{
205+
public required string ClientId { get; set; }
206+
public required string ClientSecret { get; set; }
207+
}
208+
209+
// Configuration Models
210+
public class TranslationConfiguration
211+
{
212+
public int MaxFileSizeBytes { get; set; } = 40 * 1024 * 1024; // 40MB (Azure limit)
213+
public int MaxDocumentsPerJob { get; set; } = 50;
214+
public int JobTimeoutMinutes { get; set; } = 60;
215+
public List<string> SupportedFileTypes { get; set; } = new()
216+
{
217+
".docx", ".xlsx", ".pptx", ".pdf", ".html", ".htm",
218+
".txt", ".md", ".msg", ".odt", ".ods", ".odp"
219+
};
220+
public string SourceContainerName { get; set; } = "translation-source";
221+
public string TargetContainerPrefix { get; set; } = "translation-target-";
222+
public bool DeleteBlobsAfterProcessing { get; set; } = true;
223+
public int BlobSasExpiryHours { get; set; } = 2;
224+
public int StatusPollingIntervalSeconds { get; set; } = 5;
225+
}
226+
227+
/// <summary>
228+
/// Represents an error that occurred during document translation.
229+
/// </summary>
230+
public class DocumentTranslationError
231+
{
232+
public string Code { get; set; } = string.Empty;
233+
public string Message { get; set; } = string.Empty;
234+
public string? Target { get; set; }
235+
}

0 commit comments

Comments
 (0)