diff --git a/MetadataTranslator/Metadata Translator.sln b/MetadataTranslator/Metadata Translator.sln
new file mode 100644
index 0000000..2c72677
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metadata Translator", "Metadata Translator\Metadata Translator.csproj", "{CB7D493C-B67E-4438-B304-EFE5D418ADDF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CB7D493C-B67E-4438-B304-EFE5D418ADDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CB7D493C-B67E-4438-B304-EFE5D418ADDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CB7D493C-B67E-4438-B304-EFE5D418ADDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CB7D493C-B67E-4438-B304-EFE5D418ADDF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0733CEFA-6458-4D8F-B498-FC9827973880}
+ EndGlobalSection
+EndGlobal
diff --git a/MetadataTranslator/Metadata Translator/App.config b/MetadataTranslator/Metadata Translator/App.config
new file mode 100644
index 0000000..1e2eb3b
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/App.config
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/App.xaml b/MetadataTranslator/Metadata Translator/App.xaml
new file mode 100644
index 0000000..bd6ce63
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/App.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/MetadataTranslator/Metadata Translator/App.xaml.cs b/MetadataTranslator/Metadata Translator/App.xaml.cs
new file mode 100644
index 0000000..268b902
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/App.xaml.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Metadata_Translator
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ private void Application_Startup(object sender, StartupEventArgs e)
+ {
+ MainWindow mainWindow = new MainWindow(e);
+ mainWindow.Show();
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Converters/CollectionEmptyTrueFalseConverter.cs b/MetadataTranslator/Metadata Translator/Converters/CollectionEmptyTrueFalseConverter.cs
new file mode 100644
index 0000000..343e0ec
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Converters/CollectionEmptyTrueFalseConverter.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Metadata_Translator
+{
+ public class CollectionEmptyTrueFalseConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (value is ObservableCollection collection) ? collection.Count > 0 : false;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+}
diff --git a/MetadataTranslator/Metadata Translator/Converters/PercentageConverter.cs b/MetadataTranslator/Metadata Translator/Converters/PercentageConverter.cs
new file mode 100644
index 0000000..ea8804f
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Converters/PercentageConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Metadata_Translator
+{
+ public class PercentageConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is Double size)
+ {
+ return size * 0.5;
+ }
+ return value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Converters/TranslationPropertyToolTipConverter.cs b/MetadataTranslator/Metadata Translator/Converters/TranslationPropertyToolTipConverter.cs
new file mode 100644
index 0000000..d324b5c
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Converters/TranslationPropertyToolTipConverter.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Metadata_Translator
+{
+ public class TranslationPropertyToolTipConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if(parameter is string toolTipString)
+ {
+ string[] toolTip = toolTipString.Split('|');
+ if (value is ObservableCollection collection && toolTip?.Length == 2)
+ {
+ return collection.Count > 0 ? toolTip[0] : toolTip[1];
+ }
+ else
+ return toolTipString;
+ }
+
+ return string.Empty;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Converters/TrueFalseVisibilityConverter.cs b/MetadataTranslator/Metadata Translator/Converters/TrueFalseVisibilityConverter.cs
new file mode 100644
index 0000000..55a6015
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Converters/TrueFalseVisibilityConverter.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Metadata_Translator
+{
+ class TrueFalseVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (System.Convert.ToBoolean(value))? Visibility.Collapsed : Visibility.Visible;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class FalseTrueVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (System.Convert.ToBoolean(value)) ? Visibility.Visible : Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Data/CsvRow.cs b/MetadataTranslator/Metadata Translator/Data/CsvRow.cs
new file mode 100644
index 0000000..1559136
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Data/CsvRow.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class CsvRow
+ {
+ public string Type { get; set; }
+ public string Original { get; set; }
+ public string Translation { get; set; }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Data/DataModel.cs b/MetadataTranslator/Metadata Translator/Data/DataModel.cs
new file mode 100644
index 0000000..af360dd
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Data/DataModel.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AS = Microsoft.AnalysisServices;
+using Microsoft.AnalysisServices.Tabular;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.Dynamic;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.IO;
+using System.Web.Script.Serialization;
+using Microsoft.VisualBasic.FileIO;
+
+namespace Metadata_Translator
+{
+ public class DataModel
+ {
+ Model Model { get; set; }
+
+ public string ContainerColumnHeader { get => "Object"; }
+ public ObservableCollection Captions { get; private set; }
+ public ObservableCollection Descriptions { get; private set; }
+ public ObservableCollection DisplayFolders { get; private set; }
+
+ public string DefaultCulture { get; set; }
+
+ public List CultureNames
+ {
+ get
+ {
+ List cultures = new List { Model.Culture };
+ cultures.AddRange(Model?.Cultures.Where(i => !i.Name.Equals(Model.Culture)).Select(x => x.Name).ToList());
+ return cultures;
+ }
+ }
+ public List SupportedLanguages { get; private set; }
+ public List SelectedLanguages { get => SupportedLanguages?.Where(x => x.IsSelected==true).ToList(); }
+ public bool HasTargetLanguages { get => SelectedLanguages?.Count > 1; }
+
+ public DataModel(string server, string database)
+ {
+ LoadLanguages();
+
+ Server pbiDesktop = new Server();
+ pbiDesktop.Connect($"Data Source={server}");
+ Database dataset = pbiDesktop.Databases.GetByName(database);
+ Model = dataset.Model;
+
+ DefaultCulture = Model.Culture;
+
+ LoadNamedObjectCollections();
+ }
+
+ ///
+ /// A static helper to get the DataModel object.
+ ///
+ ///
+ ///
+ ///
+ public static DataModel Connect(string server, string database)
+ {
+ return new DataModel(server, database);
+ }
+
+ ///
+ /// Gets the tables from the dataset and within it all the columns, measures, and hierarchies
+ /// and adds these tabular objects to the collections for captions, descriptions, and display folders.
+ ///
+ private void LoadNamedObjectCollections()
+ {
+ Captions = new ObservableCollection();
+ Descriptions = new ObservableCollection();
+ DisplayFolders = new ObservableCollection();
+
+ CultureCollection cultures = Model.Cultures;
+
+ Captions.Add(CreateRow(new MetadataObjectContainer(Model, TranslatedProperty.Caption), Model.Name, DefaultCulture, cultures));
+ if (!string.IsNullOrEmpty(Model.Description))
+ Descriptions.Add(CreateRow(new MetadataObjectContainer(Model, TranslatedProperty.Description), Model.Description, DefaultCulture, cultures));
+
+ foreach (Table table in Model.Tables)
+ {
+ Captions.Add(CreateRow(new MetadataObjectContainer(table, TranslatedProperty.Caption), table.Name, DefaultCulture, cultures));
+ if (!string.IsNullOrEmpty(table.Description))
+ Descriptions.Add(CreateRow(new MetadataObjectContainer(table, TranslatedProperty.Description), table.Description, DefaultCulture, cultures));
+ foreach (Column column in table.Columns)
+ {
+ if (column.Type != ColumnType.RowNumber)
+ {
+ Captions.Add(CreateRow(new MetadataObjectContainer(column, TranslatedProperty.Caption), column.Name, DefaultCulture, cultures));
+
+ if (!string.IsNullOrEmpty(column.Description))
+ Descriptions.Add(CreateRow(new MetadataObjectContainer(column, TranslatedProperty.Description), column.Description, DefaultCulture, cultures));
+ if (!string.IsNullOrEmpty(column.DisplayFolder))
+ DisplayFolders.AddDisplayFolder(column, column.DisplayFolder, DefaultCulture, cultures);
+ }
+ }
+
+ foreach (Measure measure in table.Measures)
+ {
+ Captions.Add(CreateRow(new MetadataObjectContainer(measure, TranslatedProperty.Caption), measure.Name, DefaultCulture, cultures));
+
+ if (!string.IsNullOrEmpty(measure.Description))
+ Descriptions.Add(CreateRow(new MetadataObjectContainer(measure, TranslatedProperty.Description), measure.Description, DefaultCulture, cultures));
+ if (!string.IsNullOrEmpty(measure.DisplayFolder))
+ DisplayFolders.AddDisplayFolder(measure, measure.DisplayFolder, DefaultCulture, cultures);
+ }
+
+ foreach (Hierarchy hierarchy in table.Hierarchies)
+ {
+ Captions.Add(CreateRow(new MetadataObjectContainer(hierarchy, TranslatedProperty.Caption), hierarchy.Name, DefaultCulture, cultures));
+
+ if (!string.IsNullOrEmpty(hierarchy.Description))
+ Descriptions.Add(CreateRow(new MetadataObjectContainer(hierarchy, TranslatedProperty.Description), hierarchy.Description, DefaultCulture, cultures));
+ if (!string.IsNullOrEmpty(hierarchy.DisplayFolder))
+ DisplayFolders.AddDisplayFolder(hierarchy, hierarchy.DisplayFolder, DefaultCulture, cultures);
+ }
+ }
+ }
+
+ ///
+ /// Loads the list of supported languages from the supportedlanguages.json file.
+ ///
+ private void LoadLanguages()
+ {
+ SupportedLanguages = new List();
+ string content = File.ReadAllText($"{System.AppDomain.CurrentDomain.BaseDirectory}Resources\\supportedlanguages.json");
+ foreach (Language lang in new JavaScriptSerializer().Deserialize>(content))
+ {
+ SupportedLanguages.Add(lang);
+ }
+ }
+
+ ///
+ /// Creates a new ExpandoObject for a source string (displayString).
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// An ExpandoObject representing a data row.
+ public ExpandoObject CreateRow(MetadataObjectContainer objectContainer, string displayString, string defaultCulture, CultureCollection cultures)
+ {
+ dynamic row = new ExpandoObject();
+
+ ((IDictionary)row)[ContainerColumnHeader] = objectContainer;
+ foreach (var culture in cultures)
+ {
+ ((IDictionary)row)[culture.Name] = culture.Name.Equals(defaultCulture) ? displayString :
+ culture.ObjectTranslations[objectContainer.TabularObject, objectContainer.TranslatedProperty]?.Value;
+ }
+
+ return row;
+ }
+
+ ///
+ /// Combine all collections for translation and updating.
+ ///
+ ///
+ public List GetAllDataRows()
+ {
+ var allRows = new List();
+ foreach (var item in Captions) allRows.Add(item);
+ foreach (var item in Descriptions) allRows.Add(item);
+ foreach (var item in DisplayFolders) allRows.Add(item);
+ return allRows;
+ }
+
+ ///
+ /// Adds a translation to a Tabular metadata object.
+ ///
+ ///
+ ///
+ ///
+ private void SetTranslation(Culture culture, MetadataObjectContainer metadataObjectContainer, string translation)
+ {
+ culture.ObjectTranslations.SetTranslation(
+ metadataObjectContainer.TabularObject, metadataObjectContainer.TranslatedProperty,
+ translation);
+ }
+
+ ///
+ /// Updates the Power BI dataset with the translations from the ExpandoObject collections and saves the changes.
+ ///
+ public void Update()
+ {
+ /// Delete any deselected cultures that still exist in the dataset.
+ ///
+ List cultureNames = SelectedLanguages?.Select(sl => sl.LanguageTag)?.ToList();
+
+ /// There must be at least the default culture in the cultureNames.
+ ///
+ if (cultureNames == null || cultureNames.Count < 1) return;
+
+ var culturesToRemove = CultureNames.Where(cn1 => !cultureNames.Any(cn2 => cn2.Equals(cn1))).ToList();
+ culturesToRemove.Remove(DefaultCulture);
+
+ foreach(string cultureName in culturesToRemove)
+ {
+ if (Model.Cultures.Contains(cultureName))
+ {
+ Model.Cultures.Remove(cultureName);
+ }
+ }
+
+ /// Add any newly selected cultures.
+ ///
+ foreach (string cultureName in cultureNames)
+ {
+ if (!Model.Cultures.Contains(cultureName))
+ {
+ Model.Cultures.Add(new Culture { Name = cultureName });
+ }
+ }
+
+ /// Add the translations to all the metadata objects.
+ ///
+ foreach (ExpandoObject row in GetAllDataRows())
+ {
+ if (((IDictionary)row)[ContainerColumnHeader] is MetadataObjectContainer metadataObjectContainer)
+ {
+ /*
+ * Include this part when updating the default culture (i.e. updating the actual metadata objects) is supported.
+ *
+ switch (metadataObjectContainer.TranslatedProperty)
+ {
+ case TranslatedProperty.Caption:
+ metadataObjectContainer.TabularObject.Name = row.GetValue(DefaultCulture);
+ break;
+ case TranslatedProperty.Description:
+ if (metadataObjectContainer.TabularObject is Table table)
+ {
+ table.Description = row.GetValue(DefaultCulture);
+ }
+ else if (metadataObjectContainer.TabularObject is Column col)
+ {
+ col.Description = row.GetValue(DefaultCulture);
+ }
+ else if (metadataObjectContainer.TabularObject is Measure measure)
+ {
+ measure.Description = row.GetValue(DefaultCulture);
+ }
+ else if (metadataObjectContainer.TabularObject is Hierarchy hierarchy)
+ {
+ hierarchy.Description = row.GetValue(DefaultCulture);
+ }
+ break;
+ case TranslatedProperty.DisplayFolder:
+ if (metadataObjectContainer.TabularObject is Column column)
+ {
+ column.DisplayFolder = row.GetValue(DefaultCulture);
+ }
+ else if (metadataObjectContainer.TabularObject is Measure measure)
+ {
+ measure.DisplayFolder = row.GetValue(DefaultCulture);
+ }
+ else if (metadataObjectContainer.TabularObject is Hierarchy hierarchy)
+ {
+ hierarchy.DisplayFolder = row.GetValue(DefaultCulture);
+ }
+ break;
+ }
+ */
+ foreach (string cultureName in cultureNames)
+ {
+ SetTranslation(Model.Cultures[cultureName],
+ metadataObjectContainer,
+ row.GetValue(cultureName));
+ }
+ }
+ }
+
+ /// Save the changes in the dataset.
+ ///
+ Model.Database.Update(AS.UpdateOptions.ExpandFull);
+ }
+
+ ///
+ /// Exports the translations to individual language files.
+ /// The files are placed into the specified export folder.
+ ///
+ ///
+ public void ExportToCsv(string exportFolderPath)
+ {
+ string separator = ",";
+ List dataRows = GetAllDataRows();
+ if (dataRows != null && dataRows.Count > 0)
+ {
+ List languages = SelectedLanguages.Where(l => l.IsModelDefault != true).Select(l => l.LanguageTag).ToList();
+
+ if (languages != null && languages.Count > 0)
+ {
+ foreach (string lcid in languages)
+ {
+ StringBuilder csvContent = new StringBuilder();
+ csvContent.AppendLine("Type,Original,Translation");
+
+ foreach (var stringValues in dataRows.GetValues(ContainerColumnHeader, DefaultCulture, lcid))
+ {
+ csvContent.AppendLine(
+ string.Join(
+ separator,
+ new string[] {
+ stringValues.Type.ToCsvString(),
+ stringValues.Original.ToCsvString(),
+ stringValues.Translation.ToCsvString()
+ })
+ );
+ }
+
+ using (var sw = File.Create(System.IO.Path.Combine(exportFolderPath, $"{lcid}.csv")))
+ {
+ var preamble = Encoding.UTF8.GetPreamble();
+ sw.Write(preamble, 0, preamble.Length);
+ var data = Encoding.UTF8.GetBytes(csvContent.ToString());
+ sw.Write(data, 0, data.Length);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Imports translations from a csv file. The file name must match the LCID of the target language.
+ ///
+ ///
+ ///
+ ///
+ public void ImportFromCsv(string filePath, string lcid, bool replaceExistingTranslations)
+ {
+ try
+ {
+ string csvData = File.ReadAllText(filePath);
+ if (string.IsNullOrEmpty(csvData)) return;
+
+ List parsedRows = new List();
+
+ using (TextFieldParser parser = new TextFieldParser(new StringReader(csvData)))
+ {
+ parser.CommentTokens = new string[] { "#" };
+ parser.SetDelimiters(new string[] { "," });
+ parser.HasFieldsEnclosedInQuotes = true;
+
+ /// Skip the header row.
+ ///
+ parser.ReadFields();
+ while (!parser.EndOfData)
+ {
+ var textFields = parser.ReadFields();
+ if (textFields != null && textFields.Count() == 3)
+ {
+ parsedRows.Add(new CsvRow
+ {
+ Type = textFields[0],
+ Original = textFields[1],
+ Translation = textFields[2]
+ });
+ }
+ }
+ }
+
+ ApplyTranslation(lcid, parsedRows, replaceExistingTranslations);
+ }
+ catch { }
+ }
+
+ ///
+ /// Applies a list of translations to the ExpandoObject collections
+ ///
+ ///
+ ///
+ ///
+ private void ApplyTranslation(string lcid, List translatedRows, bool replaceExistingTranslations)
+ {
+ var allDataRows = GetAllDataRows();
+ if(!MatchAllRows(allDataRows, lcid, translatedRows, replaceExistingTranslations))
+ {
+ /// Not all rows matched, so let's do this the slow way
+ /// matching strings.
+ ///
+ foreach(ExpandoObject row in allDataRows)
+ {
+ var metaContainer = (MetadataObjectContainer)row.GetObject(ContainerColumnHeader);
+ var original = row.GetValue(DefaultCulture);
+ var csvRow = translatedRows.Where(x => x.Type == metaContainer.TranslatedProperty.ToString() && x.Original.Equals(original)).FirstOrDefault();
+ if(csvRow != null)
+ {
+ row.SetValue(lcid, csvRow.Translation, replaceExistingTranslations);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Iterates over the dataRows and applies the translated strings with the assumption that
+ /// translatedRows matches the dataRows in number and order.
+ ///
+ private bool MatchAllRows(List dataRows, string lcid, List translatedRows, bool replaceExistingTranslations)
+ {
+ if(dataRows == null || dataRows.Count != translatedRows?.Count)
+ return false;
+
+ for(int i = 0; i < translatedRows.Count; i++)
+ {
+ ExpandoObject row = dataRows[i];
+ CsvRow csvRow = translatedRows[i];
+
+ if (row.GetValue(DefaultCulture) != csvRow.Original)
+ return false;
+
+ row.SetValue(lcid, csvRow.Translation, replaceExistingTranslations);
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Data/DisplayFolderContainer.cs b/MetadataTranslator/Metadata Translator/Data/DisplayFolderContainer.cs
new file mode 100644
index 0000000..ce03d0a
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Data/DisplayFolderContainer.cs
@@ -0,0 +1,28 @@
+using Microsoft.AnalysisServices.Tabular;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class DisplayFolderContainer : MetadataObjectContainer
+ {
+ public override NamedMetadataObject TabularObject { get => TabularObjects.FirstOrDefault(); protected set { } }
+ public List TabularObjects { get; private set; }
+
+ public DisplayFolderContainer(NamedMetadataObject metadataObject, TranslatedProperty translatedProperty) : base(metadataObject, translatedProperty)
+ {
+ TabularObjects = new List();
+ TabularObjects.Add(metadataObject);
+ }
+
+ public override string ToString()
+ {
+ return (TabularObjects.Count > 1)?
+ $"DisplayFolder - {TabularObjects.Count} Objects" :
+ $"DisplayFolder - 1 {TabularObject.ObjectType}";
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Data/MetadataObjectContainer.cs b/MetadataTranslator/Metadata Translator/Data/MetadataObjectContainer.cs
new file mode 100644
index 0000000..316029d
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Data/MetadataObjectContainer.cs
@@ -0,0 +1,35 @@
+using Microsoft.AnalysisServices.Tabular;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class MetadataObjectContainer
+ {
+ public virtual NamedMetadataObject TabularObject { get; protected set; }
+ public TranslatedProperty TranslatedProperty { get; protected set; }
+ public MetadataObjectContainer(NamedMetadataObject metadataObject, TranslatedProperty translatedProperty)
+ {
+ TabularObject = metadataObject;
+ TranslatedProperty = translatedProperty;
+ }
+
+ public override string ToString()
+ {
+ switch(TranslatedProperty)
+ {
+ case TranslatedProperty.Caption:
+ return $"{TabularObject.ObjectType} - Caption";
+ case TranslatedProperty.Description:
+ return $"{TabularObject.ObjectType} - Description";
+ case TranslatedProperty.DisplayFolder:
+ return $"{TabularObject.ObjectType} - DisplayFolder";
+ default:
+ return TabularObject.ObjectType.ToString();
+ }
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Helpers/ExpandoObjectExtensions.cs b/MetadataTranslator/Metadata Translator/Helpers/ExpandoObjectExtensions.cs
new file mode 100644
index 0000000..5761539
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Helpers/ExpandoObjectExtensions.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public static class ExpandoObjectExtensions
+ {
+ public static string SeparateCamelCase(this ExpandoObject expando, string columnName)
+ {
+ if (expando != null && ((IDictionary)expando)[columnName] is string text)
+ {
+ char separator = ' ';
+ char lastChar = separator;
+
+ var sb = new StringBuilder();
+ foreach (var currentChar in text.Replace("_", ""))
+ {
+ if (char.IsUpper(currentChar) && lastChar != separator)
+ sb.Append(separator);
+
+ sb.Append(currentChar);
+
+ lastChar = currentChar;
+ }
+
+ return sb.ToString();
+ }
+ return string.Empty;
+ }
+
+ public static string GetValue(this ExpandoObject expando, string columnName)
+ {
+ return expando.GetObject(columnName)?.ToString();
+ }
+
+ public static object GetObject(this ExpandoObject expando, string columnName)
+ {
+ if (expando != null && ((IDictionary)expando).ContainsKey(columnName))
+ {
+ return ((IDictionary)expando)[columnName];
+ }
+ return null;
+ }
+
+ public static void SetValue(this ExpandoObject expando, string columnName, string value, bool overwrite)
+ {
+ if (expando != null)
+ {
+ if (overwrite || string.IsNullOrEmpty(expando.GetValue(columnName)))
+ {
+ ((IDictionary)expando)[columnName] = value;
+ }
+ }
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Helpers/Hourglass.cs b/MetadataTranslator/Metadata Translator/Helpers/Hourglass.cs
new file mode 100644
index 0000000..7874d25
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Helpers/Hourglass.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace Metadata_Translator
+{
+ public class Hourglass : IDisposable
+ {
+ private Cursor previousCursor;
+
+ public Hourglass()
+ {
+ previousCursor = Mouse.OverrideCursor;
+ Mouse.OverrideCursor = Cursors.Wait;
+ }
+
+ public void Dispose()
+ {
+ Mouse.OverrideCursor = previousCursor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Helpers/ListExtensions.cs b/MetadataTranslator/Metadata Translator/Helpers/ListExtensions.cs
new file mode 100644
index 0000000..7190aeb
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Helpers/ListExtensions.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Dynamic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public static class ListExtensions
+ {
+ public static List GetValues(this List collection, string containerColumnName, string referenceColumnName, string columnName)
+ {
+ if (collection == null) return new List();
+
+ var values = new List();
+ foreach (ExpandoObject row in collection)
+ {
+ var metaContainer = (MetadataObjectContainer)row.GetObject(containerColumnName);
+ string refValue = row.GetValue(referenceColumnName);
+
+ if (!string.IsNullOrEmpty(refValue))
+ values.Add(new CsvRow { Type = metaContainer.TranslatedProperty.ToString(), Original = refValue, Translation = row.GetValue(columnName) });
+ }
+ return values;
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Helpers/ObservableCollectionExtensions.cs b/MetadataTranslator/Metadata Translator/Helpers/ObservableCollectionExtensions.cs
new file mode 100644
index 0000000..88ca394
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Helpers/ObservableCollectionExtensions.cs
@@ -0,0 +1,95 @@
+using Microsoft.AnalysisServices.Tabular;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Dynamic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public static class ObservableCollectionExtensions
+ {
+ public static string GetValueAt(this ObservableCollection collection, int index, string columnName)
+ {
+ if (collection == null) return string.Empty;
+
+ ExpandoObject row = collection[index];
+ return ((IDictionary)row)[columnName]?.ToString();
+ }
+
+ public static void SetValueAt(this ObservableCollection collection, int index, string columnName, string value)
+ {
+ if (collection == null) return;
+
+ ExpandoObject row = collection[index];
+ ((IDictionary)row)[columnName] = value;
+ }
+
+ public static void UpdateDataValues(this ObservableCollection collection, List sourcePhrases, string sourceLanguage, List targetPhrases, string targetLanguage)
+ {
+ if (collection == null) return;
+ int rowOffset = 0;
+ for (int i = 0; i < collection.Count; i++)
+ {
+ string columnValue = collection.GetValueAt(i, sourceLanguage);
+ if (!string.IsNullOrEmpty(columnValue) && columnValue.Equals(sourcePhrases[i - rowOffset]))
+ {
+ collection.SetValueAt(i, targetLanguage, targetPhrases[i - rowOffset]);
+ }
+ else
+ {
+ rowOffset++;
+ }
+ }
+ }
+
+ public static List GetValues(this ObservableCollection collection, string columnName)
+ {
+ if (collection == null) return new List();
+
+ List values = new List();
+ foreach (ExpandoObject row in collection)
+ {
+ string value = ((IDictionary)row)[columnName]?.ToString();
+
+ if (!string.IsNullOrEmpty(value))
+ values.Add(value);
+ }
+ return values;
+ }
+
+ public static void AddDisplayFolder(this ObservableCollection collection, NamedMetadataObject metadataObject, string displayString, string defaultCulture, CultureCollection cultures)
+ {
+ if (collection == null) return;
+
+ if (!string.IsNullOrEmpty(displayString))
+ {
+ foreach (ExpandoObject item in collection)
+ {
+ if (((IDictionary)item)[defaultCulture] is string displayName && displayName.Equals(displayString))
+ {
+ var existingDisplayFolderContainer = ((IDictionary)item)["Object"] as DisplayFolderContainer;
+ existingDisplayFolderContainer.TabularObjects.Add(metadataObject);
+ return;
+ }
+ }
+ }
+
+ dynamic row = new ExpandoObject();
+ var displayFolderContainer = new DisplayFolderContainer(metadataObject, TranslatedProperty.DisplayFolder);
+
+ ((IDictionary)row)["Object"] = displayFolderContainer;
+ foreach (var culture in cultures)
+ {
+ ((IDictionary)row)[culture.Name] = culture.Name.Equals(defaultCulture) ? displayString :
+ culture.ObjectTranslations[displayFolderContainer.TabularObject, displayFolderContainer.TranslatedProperty]?.Value;
+ }
+
+ collection.Add(row);
+ }
+
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Helpers/StringExtensions.cs b/MetadataTranslator/Metadata Translator/Helpers/StringExtensions.cs
new file mode 100644
index 0000000..794b895
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Helpers/StringExtensions.cs
@@ -0,0 +1,21 @@
+using Microsoft.AnalysisServices.Tabular;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Dynamic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public static class StringExtensions
+ {
+ public static string ToCsvString(this string value)
+ {
+ if (value == null) return string.Empty;
+ return value.Contains("\"") ? $"\"{value.Replace("\"", "\"\"")}\"" : value;
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Metadata Translator.csproj b/MetadataTranslator/Metadata Translator/Metadata Translator.csproj
new file mode 100644
index 0000000..29a02c3
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Metadata Translator.csproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {CB7D493C-B67E-4438-B304-EFE5D418ADDF}
+ WinExe
+ Metadata_Translator
+ Metadata Translator
+ v4.7.2
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ icon.ico
+
+
+
+ ..\packages\Microsoft.AnalysisServices.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.dll
+
+
+ ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll
+
+
+ ..\packages\Microsoft.AnalysisServices.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.Core.dll
+
+
+ ..\packages\Microsoft.AnalysisServices.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll
+
+
+ ..\packages\Microsoft.AnalysisServices.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.Tabular.dll
+
+
+ ..\packages\Microsoft.AnalysisServices.retail.amd64.19.16.3\lib\net45\Microsoft.AnalysisServices.Tabular.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+ ImportExportPanel.xaml
+
+
+
+ LanguagePanel.xaml
+
+
+
+ SettingsPanel.xaml
+
+
+
+ TranslationGroupPanel.xaml
+
+
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+
+ MainWindow.xaml
+ Code
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Properties/AssemblyInfo.cs b/MetadataTranslator/Metadata Translator/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b6c04fd
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Metadata Translator")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Metadata Translator")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/MetadataTranslator/Metadata Translator/Properties/Resources.Designer.cs b/MetadataTranslator/Metadata Translator/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..8fb55e3
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Properties/Resources.Designer.cs
@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+//
+// 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 Metadata_Translator.Properties
+{
+ ///
+ /// 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", "4.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 ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Metadata_Translator.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;
+ }
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Properties/Resources.resx b/MetadataTranslator/Metadata Translator/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Properties/Settings.Designer.cs b/MetadataTranslator/Metadata Translator/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..1818ecf
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Properties/Settings.Designer.cs
@@ -0,0 +1,29 @@
+//------------------------------------------------------------------------------
+//
+// 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 Metadata_Translator.Properties
+{
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Properties/Settings.settings b/MetadataTranslator/Metadata Translator/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Resources/StringDictionary.xaml b/MetadataTranslator/Metadata Translator/Resources/StringDictionary.xaml
new file mode 100644
index 0000000..a3acf46
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Resources/StringDictionary.xaml
@@ -0,0 +1,43 @@
+
+ Languages
+ Opens the Languages pane to choose the target languages.
+ Settings
+ Opens the Settings pane to configure Machine Translator.
+ Translated Property
+ Caption
+ Displays the captions of the metadata objects and their translations.
+ Description
+ Displays the descriptions of the metadata objects and their translations.|The metadata objects in the current dataset have no descriptions. Use Power BI Desktop to add descriptions.
+ DisplayFolder
+ Displays the display folder names of the metadata objects and their translations.|The current dataset does not have display folders. Use Power BI Desktop to group columns and measures in display folders.
+ Prepare
+ Translate
+ Translates the captions, descriptions, and display folder names using Microsoft Translator.
+ Apply
+ Applies the translated captions, descriptions, and display folder names to the Power BI dataset.
+ Import/Export
+ Opens the Import/Export pane to export and import the captions, descriptions, and display folder names via .csv files.
+ Metadata Translator cannot start without server and database arguments. Double-check the 'arguments' setting in the metadata-translator.pbitool.json file in your Microsoft Shared\Power BI Desktop\External Tools folder. The value must be: "\"%server%\" \"%database%\"".
+ Dataset Connection String
+ Translator Subscription Key
+ Translator Endpoint
+ Translator Location
+ Overwrite Translation
+ Enter your Microsoft Translator service subscription key.
+ Enter the Microsoft Translator URL, specifically: https://api.cognitive.microsofttranslator.com/
+ This is typically the Global region, but could also be a single Azure region.
+ Please select at least one language before you translate the metadata.
+ Microsoft Translator was unable to translate the metadata strings into {0}. Please try again later or remove this language from the translation.
+ Export .csv files
+ You can export the metadata captions, descriptions, and display folder strings into .csv files based on the locale identifiers (LCIDs) of the selected languages. Metadata Translator creates a separate .csv file for each LCID.
+ Select the folder where you want to store your .csv files. Note that Metadata Translator might overwrite any existing files in this folder.
+ Export...
+ Import .csv files
+ You can import translated captions, descriptions, and display folder strings from .csv files. Each file name must match a locale identifier (LCID) of a supported language. You can import multiple .csv files in a single step.
+ Import...
+ Object - Type
+ The default culture is read-only. Use Power BI Desktop to change the names, descriptions, and display folder names for the default culture.
+
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Resources/supportedlanguages.json b/MetadataTranslator/Metadata Translator/Resources/supportedlanguages.json
new file mode 100644
index 0000000..9724a7f
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Resources/supportedlanguages.json
@@ -0,0 +1,2361 @@
+[
+ {
+ "LanguageTag": "af-NA",
+ "TranslationId": "af",
+ "TranslationGroup": "Afrikaans",
+ "DisplayName": "Afrikaans (Namibia)",
+ "NativeName": "Afrikaans (Namibië)"
+ },
+ {
+ "LanguageTag": "af-ZA",
+ "TranslationId": "af",
+ "TranslationGroup": "Afrikaans",
+ "DisplayName": "Afrikaans (South Africa)",
+ "NativeName": "Afrikaans (Suid-Afrika)"
+ },
+ {
+ "LanguageTag": "bs-Latn-BA",
+ "TranslationId": "bs",
+ "TranslationGroup": "Bosnian (Latin)",
+ "DisplayName": "Bosnian (Latin, Bosnia & Herzegovina)",
+ "NativeName": "bosanski (Bosna i Hercegovina)"
+ },
+ {
+ "LanguageTag": "ar-001",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (World)",
+ "NativeName": "العربية (العالم)"
+ },
+ {
+ "LanguageTag": "ar-AE",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (United Arab Emirates)",
+ "NativeName": "العربية (الإمارات العربية المتحدة)"
+ },
+ {
+ "LanguageTag": "ar-BH",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Bahrain)",
+ "NativeName": "العربية (البحرين)"
+ },
+ {
+ "LanguageTag": "ar-DJ",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Djibouti)",
+ "NativeName": "العربية (جيبوتي)"
+ },
+ {
+ "LanguageTag": "ar-DZ",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Algeria)",
+ "NativeName": "العربية (الجزائر)"
+ },
+ {
+ "LanguageTag": "ar-EG",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Egypt)",
+ "NativeName": "العربية (مصر)"
+ },
+ {
+ "LanguageTag": "ar-ER",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Eritrea)",
+ "NativeName": "العربية (إريتريا)"
+ },
+ {
+ "LanguageTag": "ar-IL",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Israel)",
+ "NativeName": "العربية (إسرائيل)"
+ },
+ {
+ "LanguageTag": "ar-IQ",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Iraq)",
+ "NativeName": "العربية (العراق)"
+ },
+ {
+ "LanguageTag": "ar-JO",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Jordan)",
+ "NativeName": "العربية (الأردن)"
+ },
+ {
+ "LanguageTag": "ar-KM",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Comoros)",
+ "NativeName": "العربية (جزر القمر)"
+ },
+ {
+ "LanguageTag": "ar-KW",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Kuwait)",
+ "NativeName": "العربية (الكويت)"
+ },
+ {
+ "LanguageTag": "ar-LB",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Lebanon)",
+ "NativeName": "العربية (لبنان)"
+ },
+ {
+ "LanguageTag": "ar-LY",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Libya)",
+ "NativeName": "العربية (ليبيا)"
+ },
+ {
+ "LanguageTag": "ar-MA",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Morocco)",
+ "NativeName": "العربية (المملكة المغربية)"
+ },
+ {
+ "LanguageTag": "ar-MR",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Mauritania)",
+ "NativeName": "العربية (موريتانيا)"
+ },
+ {
+ "LanguageTag": "ar-OM",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Oman)",
+ "NativeName": "العربية (عمان)"
+ },
+ {
+ "LanguageTag": "ar-PS",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Palestinian Authority)",
+ "NativeName": "العربية (السلطة الفلسطينية)"
+ },
+ {
+ "LanguageTag": "ar-QA",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Qatar)",
+ "NativeName": "العربية (قطر)"
+ },
+ {
+ "LanguageTag": "ar-SA",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Saudi Arabia)",
+ "NativeName": "العربية (المملكة العربية السعودية)"
+ },
+ {
+ "LanguageTag": "ar-SD",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Sudan)",
+ "NativeName": "العربية (السودان)"
+ },
+ {
+ "LanguageTag": "ar-SO",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Somalia)",
+ "NativeName": "العربية (الصومال)"
+ },
+ {
+ "LanguageTag": "ar-SS",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (South Sudan)",
+ "NativeName": "العربية (جنوب السودان)"
+ },
+ {
+ "LanguageTag": "ar-SY",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Syria)",
+ "NativeName": "العربية (سوريا)"
+ },
+ {
+ "LanguageTag": "ar-TD",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Chad)",
+ "NativeName": "العربية (تشاد)"
+ },
+ {
+ "LanguageTag": "ar-TN",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Tunisia)",
+ "NativeName": "العربية (تونس)"
+ },
+ {
+ "LanguageTag": "ar-YE",
+ "TranslationId": "ar",
+ "TranslationGroup": "Arabic",
+ "DisplayName": "Arabic (Yemen)",
+ "NativeName": "العربية (اليمن)"
+ },
+ {
+ "LanguageTag": "as-IN",
+ "TranslationId": "as",
+ "TranslationGroup": "Assamese",
+ "DisplayName": "Assamese (India)",
+ "NativeName": "অসমীয়া (ভাৰত)"
+ },
+ {
+ "LanguageTag": "bg-BG",
+ "TranslationId": "bg",
+ "TranslationGroup": "Bulgarian",
+ "DisplayName": "Bulgarian (Bulgaria)",
+ "NativeName": "български (България)"
+ },
+ {
+ "LanguageTag": "bn-BD",
+ "TranslationId": "bn",
+ "TranslationGroup": "Bangla",
+ "DisplayName": "Bangla (Bangladesh)",
+ "NativeName": "বাংলা (বাংলাদেশ)"
+ },
+ {
+ "LanguageTag": "bn-IN",
+ "TranslationId": "bn",
+ "TranslationGroup": "Bangla",
+ "DisplayName": "Bengali (India)",
+ "NativeName": "বাংলা (ভারত)"
+ },
+ {
+ "LanguageTag": "ca-AD",
+ "TranslationId": "ca",
+ "TranslationGroup": "Catalan",
+ "DisplayName": "Catalan (Andorra)",
+ "NativeName": "català (Andorra)"
+ },
+ {
+ "LanguageTag": "ca-ES",
+ "TranslationId": "ca",
+ "TranslationGroup": "Catalan",
+ "DisplayName": "Catalan (Catalan)",
+ "NativeName": "català (català)"
+ },
+ {
+ "LanguageTag": "ca-FR",
+ "TranslationId": "ca",
+ "TranslationGroup": "Catalan",
+ "DisplayName": "Catalan (France)",
+ "NativeName": "català (França)"
+ },
+ {
+ "LanguageTag": "ca-IT",
+ "TranslationId": "ca",
+ "TranslationGroup": "Catalan",
+ "DisplayName": "Catalan (Italy)",
+ "NativeName": "català (Itàlia)"
+ },
+ {
+ "LanguageTag": "cs-CZ",
+ "TranslationId": "cs",
+ "TranslationGroup": "Czech",
+ "DisplayName": "Czech (Czechia)",
+ "NativeName": "čeština (Česko)"
+ },
+ {
+ "LanguageTag": "da-DK",
+ "TranslationId": "da",
+ "TranslationGroup": "Danish",
+ "DisplayName": "Danish (Denmark)",
+ "NativeName": "dansk (Danmark)"
+ },
+ {
+ "LanguageTag": "da-GL",
+ "TranslationId": "da",
+ "TranslationGroup": "Danish",
+ "DisplayName": "Danish (Greenland)",
+ "NativeName": "dansk (Grønland)"
+ },
+ {
+ "LanguageTag": "en-001",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (World)",
+ "NativeName": "English (World)"
+ },
+ {
+ "LanguageTag": "en-029",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Caribbean)",
+ "NativeName": "English (Caribbean)"
+ },
+ {
+ "LanguageTag": "en-150",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Europe)",
+ "NativeName": "English (Europe)"
+ },
+ {
+ "LanguageTag": "en-AE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (United Arab Emirates)",
+ "NativeName": "English (United Arab Emirates)"
+ },
+ {
+ "LanguageTag": "en-AG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Antigua & Barbuda)",
+ "NativeName": "English (Antigua & Barbuda)"
+ },
+ {
+ "LanguageTag": "en-AI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Anguilla)",
+ "NativeName": "English (Anguilla)"
+ },
+ {
+ "LanguageTag": "en-AS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (American Samoa)",
+ "NativeName": "English (American Samoa)"
+ },
+ {
+ "LanguageTag": "en-AT",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Austria)",
+ "NativeName": "English (Austria)"
+ },
+ {
+ "LanguageTag": "en-AU",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Australia)",
+ "NativeName": "English (Australia)"
+ },
+ {
+ "LanguageTag": "en-BB",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Barbados)",
+ "NativeName": "English (Barbados)"
+ },
+ {
+ "LanguageTag": "en-BE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Belgium)",
+ "NativeName": "English (Belgium)"
+ },
+ {
+ "LanguageTag": "en-BI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Burundi)",
+ "NativeName": "English (Burundi)"
+ },
+ {
+ "LanguageTag": "en-BM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Bermuda)",
+ "NativeName": "English (Bermuda)"
+ },
+ {
+ "LanguageTag": "en-BS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Bahamas)",
+ "NativeName": "English (Bahamas)"
+ },
+ {
+ "LanguageTag": "en-BW",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Botswana)",
+ "NativeName": "English (Botswana)"
+ },
+ {
+ "LanguageTag": "en-BZ",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Belize)",
+ "NativeName": "English (Belize)"
+ },
+ {
+ "LanguageTag": "en-CA",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Canada)",
+ "NativeName": "English (Canada)"
+ },
+ {
+ "LanguageTag": "en-CC",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Cocos (Keeling) Islands)",
+ "NativeName": "English (Cocos (Keeling) Islands)"
+ },
+ {
+ "LanguageTag": "en-CH",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Switzerland)",
+ "NativeName": "English (Switzerland)"
+ },
+ {
+ "LanguageTag": "en-CK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Cook Islands)",
+ "NativeName": "English (Cook Islands)"
+ },
+ {
+ "LanguageTag": "en-CM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Cameroon)",
+ "NativeName": "English (Cameroon)"
+ },
+ {
+ "LanguageTag": "en-CX",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Christmas Island)",
+ "NativeName": "English (Christmas Island)"
+ },
+ {
+ "LanguageTag": "en-CY",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Cyprus)",
+ "NativeName": "English (Cyprus)"
+ },
+ {
+ "LanguageTag": "en-DE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Germany)",
+ "NativeName": "English (Germany)"
+ },
+ {
+ "LanguageTag": "en-DK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Denmark)",
+ "NativeName": "English (Denmark)"
+ },
+ {
+ "LanguageTag": "en-DM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Dominica)",
+ "NativeName": "English (Dominica)"
+ },
+ {
+ "LanguageTag": "en-ER",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Eritrea)",
+ "NativeName": "English (Eritrea)"
+ },
+ {
+ "LanguageTag": "en-FI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Finland)",
+ "NativeName": "English (Finland)"
+ },
+ {
+ "LanguageTag": "en-FJ",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Fiji)",
+ "NativeName": "English (Fiji)"
+ },
+ {
+ "LanguageTag": "en-FK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Falkland Islands)",
+ "NativeName": "English (Falkland Islands)"
+ },
+ {
+ "LanguageTag": "de-AT",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Austria)",
+ "NativeName": "Deutsch (Österreich)"
+ },
+ {
+ "LanguageTag": "de-BE",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Belgium)",
+ "NativeName": "Deutsch (Belgien)"
+ },
+ {
+ "LanguageTag": "de-CH",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Switzerland)",
+ "NativeName": "Deutsch (Schweiz)"
+ },
+ {
+ "LanguageTag": "de-DE",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Germany)",
+ "NativeName": "Deutsch (Deutschland)"
+ },
+ {
+ "LanguageTag": "de-IT",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Italy)",
+ "NativeName": "Deutsch (Italien)"
+ },
+ {
+ "LanguageTag": "de-LI",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Liechtenstein)",
+ "NativeName": "Deutsch (Liechtenstein)"
+ },
+ {
+ "LanguageTag": "de-LU",
+ "TranslationId": "de",
+ "TranslationGroup": "German",
+ "DisplayName": "German (Luxembourg)",
+ "NativeName": "Deutsch (Luxemburg)"
+ },
+ {
+ "LanguageTag": "el-CY",
+ "TranslationId": "el",
+ "TranslationGroup": "Greek",
+ "DisplayName": "Greek (Cyprus)",
+ "NativeName": "Ελληνικά (Κύπρος)"
+ },
+ {
+ "LanguageTag": "el-GR",
+ "TranslationId": "el",
+ "TranslationGroup": "Greek",
+ "DisplayName": "Greek (Greece)",
+ "NativeName": "Ελληνικά (Ελλάδα)"
+ },
+ {
+ "LanguageTag": "cy-GB",
+ "TranslationId": "cy",
+ "TranslationGroup": "Welsh",
+ "DisplayName": "Welsh (United Kingdom)",
+ "NativeName": "Cymraeg (Y Deyrnas Unedig)"
+ },
+ {
+ "LanguageTag": "en-FM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Micronesia)",
+ "NativeName": "English (Micronesia)"
+ },
+ {
+ "LanguageTag": "en-GB",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (United Kingdom)",
+ "NativeName": "English (United Kingdom)"
+ },
+ {
+ "LanguageTag": "en-GD",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Grenada)",
+ "NativeName": "English (Grenada)"
+ },
+ {
+ "LanguageTag": "en-GG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Guernsey)",
+ "NativeName": "English (Guernsey)"
+ },
+ {
+ "LanguageTag": "en-GH",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Ghana)",
+ "NativeName": "English (Ghana)"
+ },
+ {
+ "LanguageTag": "en-GI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Gibraltar)",
+ "NativeName": "English (Gibraltar)"
+ },
+ {
+ "LanguageTag": "en-GM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Gambia)",
+ "NativeName": "English (Gambia)"
+ },
+ {
+ "LanguageTag": "en-GU",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Guam)",
+ "NativeName": "English (Guam)"
+ },
+ {
+ "LanguageTag": "en-GY",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Guyana)",
+ "NativeName": "English (Guyana)"
+ },
+ {
+ "LanguageTag": "en-HK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Hong Kong SAR)",
+ "NativeName": "English (Hong Kong SAR)"
+ },
+ {
+ "LanguageTag": "en-ID",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Indonesia)",
+ "NativeName": "English (Indonesia)"
+ },
+ {
+ "LanguageTag": "en-IE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Ireland)",
+ "NativeName": "English (Ireland)"
+ },
+ {
+ "LanguageTag": "en-IL",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Israel)",
+ "NativeName": "English (Israel)"
+ },
+ {
+ "LanguageTag": "en-IM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Isle of Man)",
+ "NativeName": "English (Isle of Man)"
+ },
+ {
+ "LanguageTag": "en-IN",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (India)",
+ "NativeName": "English (India)"
+ },
+ {
+ "LanguageTag": "en-IO",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (British Indian Ocean Territory)",
+ "NativeName": "English (British Indian Ocean Territory)"
+ },
+ {
+ "LanguageTag": "en-JE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Jersey)",
+ "NativeName": "English (Jersey)"
+ },
+ {
+ "LanguageTag": "en-JM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Jamaica)",
+ "NativeName": "English (Jamaica)"
+ },
+ {
+ "LanguageTag": "en-KE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Kenya)",
+ "NativeName": "English (Kenya)"
+ },
+ {
+ "LanguageTag": "en-KI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Kiribati)",
+ "NativeName": "English (Kiribati)"
+ },
+ {
+ "LanguageTag": "en-KN",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (St. Kitts & Nevis)",
+ "NativeName": "English (St. Kitts & Nevis)"
+ },
+ {
+ "LanguageTag": "en-KY",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Cayman Islands)",
+ "NativeName": "English (Cayman Islands)"
+ },
+ {
+ "LanguageTag": "en-LC",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (St. Lucia)",
+ "NativeName": "English (St. Lucia)"
+ },
+ {
+ "LanguageTag": "en-LR",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Liberia)",
+ "NativeName": "English (Liberia)"
+ },
+ {
+ "LanguageTag": "en-LS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Lesotho)",
+ "NativeName": "English (Lesotho)"
+ },
+ {
+ "LanguageTag": "en-MG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Madagascar)",
+ "NativeName": "English (Madagascar)"
+ },
+ {
+ "LanguageTag": "en-MH",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Marshall Islands)",
+ "NativeName": "English (Marshall Islands)"
+ },
+ {
+ "LanguageTag": "en-MO",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Macao SAR)",
+ "NativeName": "English (Macao SAR)"
+ },
+ {
+ "LanguageTag": "en-MP",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Northern Mariana Islands)",
+ "NativeName": "English (Northern Mariana Islands)"
+ },
+ {
+ "LanguageTag": "en-MS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Montserrat)",
+ "NativeName": "English (Montserrat)"
+ },
+ {
+ "LanguageTag": "en-MT",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Malta)",
+ "NativeName": "English (Malta)"
+ },
+ {
+ "LanguageTag": "en-MU",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Mauritius)",
+ "NativeName": "English (Mauritius)"
+ },
+ {
+ "LanguageTag": "en-MW",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Malawi)",
+ "NativeName": "English (Malawi)"
+ },
+ {
+ "LanguageTag": "en-MY",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Malaysia)",
+ "NativeName": "English (Malaysia)"
+ },
+ {
+ "LanguageTag": "en-NA",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Namibia)",
+ "NativeName": "English (Namibia)"
+ },
+ {
+ "LanguageTag": "en-NF",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Norfolk Island)",
+ "NativeName": "English (Norfolk Island)"
+ },
+ {
+ "LanguageTag": "en-NG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Nigeria)",
+ "NativeName": "English (Nigeria)"
+ },
+ {
+ "LanguageTag": "en-NL",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Netherlands)",
+ "NativeName": "English (Netherlands)"
+ },
+ {
+ "LanguageTag": "en-NR",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Nauru)",
+ "NativeName": "English (Nauru)"
+ },
+ {
+ "LanguageTag": "en-NU",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Niue)",
+ "NativeName": "English (Niue)"
+ },
+ {
+ "LanguageTag": "en-NZ",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (New Zealand)",
+ "NativeName": "English (New Zealand)"
+ },
+ {
+ "LanguageTag": "en-PG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Papua New Guinea)",
+ "NativeName": "English (Papua New Guinea)"
+ },
+ {
+ "LanguageTag": "en-PH",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Philippines)",
+ "NativeName": "English (Philippines)"
+ },
+ {
+ "LanguageTag": "en-PK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Pakistan)",
+ "NativeName": "English (Pakistan)"
+ },
+ {
+ "LanguageTag": "en-PN",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Pitcairn Islands)",
+ "NativeName": "English (Pitcairn Islands)"
+ },
+ {
+ "LanguageTag": "en-PR",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Puerto Rico)",
+ "NativeName": "English (Puerto Rico)"
+ },
+ {
+ "LanguageTag": "en-PW",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Palau)",
+ "NativeName": "English (Palau)"
+ },
+ {
+ "LanguageTag": "en-RW",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Rwanda)",
+ "NativeName": "English (Rwanda)"
+ },
+ {
+ "LanguageTag": "en-SB",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Solomon Islands)",
+ "NativeName": "English (Solomon Islands)"
+ },
+ {
+ "LanguageTag": "en-SC",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Seychelles)",
+ "NativeName": "English (Seychelles)"
+ },
+ {
+ "LanguageTag": "en-SD",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Sudan)",
+ "NativeName": "English (Sudan)"
+ },
+ {
+ "LanguageTag": "en-SE",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Sweden)",
+ "NativeName": "English (Sweden)"
+ },
+ {
+ "LanguageTag": "en-SG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Singapore)",
+ "NativeName": "English (Singapore)"
+ },
+ {
+ "LanguageTag": "en-SH",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (St Helena, Ascension, Tristan da Cunha)",
+ "NativeName": "English (St Helena, Ascension, Tristan da Cunha)"
+ },
+ {
+ "LanguageTag": "en-SI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Slovenia)",
+ "NativeName": "English (Slovenia)"
+ },
+ {
+ "LanguageTag": "en-SL",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Sierra Leone)",
+ "NativeName": "English (Sierra Leone)"
+ },
+ {
+ "LanguageTag": "en-SS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (South Sudan)",
+ "NativeName": "English (South Sudan)"
+ },
+ {
+ "LanguageTag": "en-SX",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Sint Maarten)",
+ "NativeName": "English (Sint Maarten)"
+ },
+ {
+ "LanguageTag": "en-SZ",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Eswatini)",
+ "NativeName": "English (Eswatini)"
+ },
+ {
+ "LanguageTag": "en-TC",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Turks & Caicos Islands)",
+ "NativeName": "English (Turks & Caicos Islands)"
+ },
+ {
+ "LanguageTag": "en-TK",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Tokelau)",
+ "NativeName": "English (Tokelau)"
+ },
+ {
+ "LanguageTag": "en-TO",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Tonga)",
+ "NativeName": "English (Tonga)"
+ },
+ {
+ "LanguageTag": "en-TT",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Trinidad & Tobago)",
+ "NativeName": "English (Trinidad & Tobago)"
+ },
+ {
+ "LanguageTag": "en-TV",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Tuvalu)",
+ "NativeName": "English (Tuvalu)"
+ },
+ {
+ "LanguageTag": "en-TZ",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Tanzania)",
+ "NativeName": "English (Tanzania)"
+ },
+ {
+ "LanguageTag": "en-UG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Uganda)",
+ "NativeName": "English (Uganda)"
+ },
+ {
+ "LanguageTag": "en-UM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (U.S. Outlying Islands)",
+ "NativeName": "English (U.S. Outlying Islands)"
+ },
+ {
+ "LanguageTag": "en-US",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (United States)",
+ "NativeName": "English (United States)"
+ },
+ {
+ "LanguageTag": "en-VC",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (St. Vincent & Grenadines)",
+ "NativeName": "English (St. Vincent & Grenadines)"
+ },
+ {
+ "LanguageTag": "en-VG",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (British Virgin Islands)",
+ "NativeName": "English (British Virgin Islands)"
+ },
+ {
+ "LanguageTag": "en-VI",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (U.S. Virgin Islands)",
+ "NativeName": "English (U.S. Virgin Islands)"
+ },
+ {
+ "LanguageTag": "en-VU",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Vanuatu)",
+ "NativeName": "English (Vanuatu)"
+ },
+ {
+ "LanguageTag": "en-WS",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Samoa)",
+ "NativeName": "English (Samoa)"
+ },
+ {
+ "LanguageTag": "en-ZA",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (South Africa)",
+ "NativeName": "English (South Africa)"
+ },
+ {
+ "LanguageTag": "en-ZM",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Zambia)",
+ "NativeName": "English (Zambia)"
+ },
+ {
+ "LanguageTag": "en-ZW",
+ "TranslationId": "en",
+ "TranslationGroup": "English",
+ "DisplayName": "English (Zimbabwe)",
+ "NativeName": "English (Zimbabwe)"
+ },
+ {
+ "LanguageTag": "es-419",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Latin America)",
+ "NativeName": "español (Latinoamérica)"
+ },
+ {
+ "LanguageTag": "es-AR",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Argentina)",
+ "NativeName": "español (Argentina)"
+ },
+ {
+ "LanguageTag": "es-BO",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Bolivia)",
+ "NativeName": "español (Bolivia)"
+ },
+ {
+ "LanguageTag": "es-BR",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Brazil)",
+ "NativeName": "español (Brasil)"
+ },
+ {
+ "LanguageTag": "es-BZ",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Belize)",
+ "NativeName": "español (Belice)"
+ },
+ {
+ "LanguageTag": "es-CL",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Chile)",
+ "NativeName": "español (Chile)"
+ },
+ {
+ "LanguageTag": "es-CO",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Colombia)",
+ "NativeName": "español (Colombia)"
+ },
+ {
+ "LanguageTag": "es-CR",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Costa Rica)",
+ "NativeName": "español (Costa Rica)"
+ },
+ {
+ "LanguageTag": "es-CU",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Cuba)",
+ "NativeName": "español (Cuba)"
+ },
+ {
+ "LanguageTag": "es-DO",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Dominican Republic)",
+ "NativeName": "español (República Dominicana)"
+ },
+ {
+ "LanguageTag": "es-EC",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Ecuador)",
+ "NativeName": "español (Ecuador)"
+ },
+ {
+ "LanguageTag": "es-ES",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Spain, International Sort)",
+ "NativeName": "español (España, alfabetización internacional)"
+ },
+ {
+ "LanguageTag": "es-GQ",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Equatorial Guinea)",
+ "NativeName": "español (Guinea Ecuatorial)"
+ },
+ {
+ "LanguageTag": "es-GT",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Guatemala)",
+ "NativeName": "español (Guatemala)"
+ },
+ {
+ "LanguageTag": "es-HN",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Honduras)",
+ "NativeName": "español (Honduras)"
+ },
+ {
+ "LanguageTag": "es-MX",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Mexico)",
+ "NativeName": "español (México)"
+ },
+ {
+ "LanguageTag": "es-NI",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Nicaragua)",
+ "NativeName": "español (Nicaragua)"
+ },
+ {
+ "LanguageTag": "es-PA",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Panama)",
+ "NativeName": "español (Panamá)"
+ },
+ {
+ "LanguageTag": "es-PE",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Peru)",
+ "NativeName": "español (Perú)"
+ },
+ {
+ "LanguageTag": "es-PH",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Philippines)",
+ "NativeName": "español (Filipinas)"
+ },
+ {
+ "LanguageTag": "es-PR",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Puerto Rico)",
+ "NativeName": "español (Puerto Rico)"
+ },
+ {
+ "LanguageTag": "es-PY",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Paraguay)",
+ "NativeName": "español (Paraguay)"
+ },
+ {
+ "LanguageTag": "es-SV",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (El Salvador)",
+ "NativeName": "español (El Salvador)"
+ },
+ {
+ "LanguageTag": "es-US",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (United States)",
+ "NativeName": "español (Estados Unidos)"
+ },
+ {
+ "LanguageTag": "es-UY",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Uruguay)",
+ "NativeName": "español (Uruguay)"
+ },
+ {
+ "LanguageTag": "es-VE",
+ "TranslationId": "es",
+ "TranslationGroup": "Spanish",
+ "DisplayName": "Spanish (Venezuela)",
+ "NativeName": "español (Venezuela)"
+ },
+ {
+ "LanguageTag": "et-EE",
+ "TranslationId": "et",
+ "TranslationGroup": "Estonian",
+ "DisplayName": "Estonian (Estonia)",
+ "NativeName": "eesti (Eesti)"
+ },
+ {
+ "LanguageTag": "fa-IR",
+ "TranslationId": "fa",
+ "TranslationGroup": "Persian",
+ "DisplayName": "Persian (Iran)",
+ "NativeName": "فارسی (ایران)"
+ },
+ {
+ "LanguageTag": "fi-FI",
+ "TranslationId": "fi",
+ "TranslationGroup": "Finnish",
+ "DisplayName": "Finnish (Finland)",
+ "NativeName": "suomi (Suomi)"
+ },
+ {
+ "LanguageTag": "fil-PH",
+ "TranslationId": "fil",
+ "TranslationGroup": "Filipino",
+ "DisplayName": "Filipino (Philippines)",
+ "NativeName": "Filipino (Pilipinas)"
+ },
+ {
+ "LanguageTag": "fr-029",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Caribbean)",
+ "NativeName": "français (caraïbes)"
+ },
+ {
+ "LanguageTag": "fr-BE",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Belgium)",
+ "NativeName": "français (Belgique)"
+ },
+ {
+ "LanguageTag": "fr-BF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Burkina Faso)",
+ "NativeName": "français (Burkina Faso)"
+ },
+ {
+ "LanguageTag": "fr-BI",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Burundi)",
+ "NativeName": "français (Burundi)"
+ },
+ {
+ "LanguageTag": "fr-BJ",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Benin)",
+ "NativeName": "français (Bénin)"
+ },
+ {
+ "LanguageTag": "fr-BL",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (St. Barthélemy)",
+ "NativeName": "français (Saint-Barthélemy)"
+ },
+ {
+ "LanguageTag": "fr-CA",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Canada)",
+ "NativeName": "français (Canada)"
+ },
+ {
+ "LanguageTag": "fr-CD",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French Congo (DRC)",
+ "NativeName": "français (Congo, République démocratique du)"
+ },
+ {
+ "LanguageTag": "fr-CF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Central African Republic)",
+ "NativeName": "français (République centrafricaine)"
+ },
+ {
+ "LanguageTag": "fr-CG",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Congo)",
+ "NativeName": "français (Congo)"
+ },
+ {
+ "LanguageTag": "fr-CH",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Switzerland)",
+ "NativeName": "français (Suisse)"
+ },
+ {
+ "LanguageTag": "fr-CI",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Côte d’Ivoire)",
+ "NativeName": "français (Côte d’Ivoire)"
+ },
+ {
+ "LanguageTag": "fr-CM",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Cameroon)",
+ "NativeName": "français (Cameroun)"
+ },
+ {
+ "LanguageTag": "fr-DJ",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Djibouti)",
+ "NativeName": "français (Djibouti)"
+ },
+ {
+ "LanguageTag": "fr-DZ",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Algeria)",
+ "NativeName": "français (Algérie)"
+ },
+ {
+ "LanguageTag": "fr-FR",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (France)",
+ "NativeName": "français (France)"
+ },
+ {
+ "LanguageTag": "fr-GA",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Gabon)",
+ "NativeName": "français (Gabon)"
+ },
+ {
+ "LanguageTag": "fr-GF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (French Guiana)",
+ "NativeName": "français (Guyane française)"
+ },
+ {
+ "LanguageTag": "fr-GN",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Guinea)",
+ "NativeName": "français (Guinée)"
+ },
+ {
+ "LanguageTag": "fr-GP",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Guadeloupe)",
+ "NativeName": "français (Guadeloupe)"
+ },
+ {
+ "LanguageTag": "fr-GQ",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Equatorial Guinea)",
+ "NativeName": "français (Guinée équatoriale)"
+ },
+ {
+ "LanguageTag": "fr-HT",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Haiti)",
+ "NativeName": "français (Haïti)"
+ },
+ {
+ "LanguageTag": "fr-KM",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Comoros)",
+ "NativeName": "français (Comores)"
+ },
+ {
+ "LanguageTag": "fr-LU",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Luxembourg)",
+ "NativeName": "français (Luxembourg)"
+ },
+ {
+ "LanguageTag": "fr-MA",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Morocco)",
+ "NativeName": "français (Maroc)"
+ },
+ {
+ "LanguageTag": "fr-MC",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Monaco)",
+ "NativeName": "français (Monaco)"
+ },
+ {
+ "LanguageTag": "fr-MF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (St. Martin)",
+ "NativeName": "français (Saint-Martin)"
+ },
+ {
+ "LanguageTag": "fr-MG",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Madagascar)",
+ "NativeName": "français (Madagascar)"
+ },
+ {
+ "LanguageTag": "fr-ML",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Mali)",
+ "NativeName": "français (Mali)"
+ },
+ {
+ "LanguageTag": "fr-MQ",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Martinique)",
+ "NativeName": "français (Martinique)"
+ },
+ {
+ "LanguageTag": "fr-MR",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Mauritania)",
+ "NativeName": "français (Mauritanie)"
+ },
+ {
+ "LanguageTag": "fr-MU",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Mauritius)",
+ "NativeName": "français (Maurice)"
+ },
+ {
+ "LanguageTag": "fr-NC",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (New Caledonia)",
+ "NativeName": "français (Nouvelle-Calédonie)"
+ },
+ {
+ "LanguageTag": "fr-NE",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Niger)",
+ "NativeName": "français (Niger)"
+ },
+ {
+ "LanguageTag": "fr-PF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (French Polynesia)",
+ "NativeName": "français (Polynésie française)"
+ },
+ {
+ "LanguageTag": "fr-PM",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (St. Pierre & Miquelon)",
+ "NativeName": "français (Saint-Pierre-et-Miquelon)"
+ },
+ {
+ "LanguageTag": "fr-RE",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Réunion)",
+ "NativeName": "français (La Réunion)"
+ },
+ {
+ "LanguageTag": "fr-RW",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Rwanda)",
+ "NativeName": "français (Rwanda)"
+ },
+ {
+ "LanguageTag": "fr-SC",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Seychelles)",
+ "NativeName": "français (Seychelles)"
+ },
+ {
+ "LanguageTag": "fr-SN",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Senegal)",
+ "NativeName": "français (Sénégal)"
+ },
+ {
+ "LanguageTag": "fr-SY",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Syria)",
+ "NativeName": "français (Syrie)"
+ },
+ {
+ "LanguageTag": "fr-TD",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Chad)",
+ "NativeName": "français (Tchad)"
+ },
+ {
+ "LanguageTag": "fr-TG",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Togo)",
+ "NativeName": "français (Togo)"
+ },
+ {
+ "LanguageTag": "fr-TN",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Tunisia)",
+ "NativeName": "français (Tunisie)"
+ },
+ {
+ "LanguageTag": "fr-VU",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Vanuatu)",
+ "NativeName": "français (Vanuatu)"
+ },
+ {
+ "LanguageTag": "fr-WF",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Wallis & Futuna)",
+ "NativeName": "français (Wallis-et-Futuna)"
+ },
+ {
+ "LanguageTag": "fr-YT",
+ "TranslationId": "fr",
+ "TranslationGroup": "French",
+ "DisplayName": "French (Mayotte)",
+ "NativeName": "français (Mayotte)"
+ },
+ {
+ "LanguageTag": "ga-IE",
+ "TranslationId": "ga",
+ "TranslationGroup": "Irish",
+ "DisplayName": "Irish (Ireland)",
+ "NativeName": "Gaeilge (Éire)"
+ },
+ {
+ "LanguageTag": "gu-IN",
+ "TranslationId": "gu",
+ "TranslationGroup": "Gujarati",
+ "DisplayName": "Gujarati (India)",
+ "NativeName": "ગુજરાતી (ભારત)"
+ },
+ {
+ "LanguageTag": "he-IL",
+ "TranslationId": "he",
+ "TranslationGroup": "Hebrew",
+ "DisplayName": "Hebrew (Israel)",
+ "NativeName": "עברית (ישראל)"
+ },
+ {
+ "LanguageTag": "hi-IN",
+ "TranslationId": "hi",
+ "TranslationGroup": "Hindi",
+ "DisplayName": "Hindi (India)",
+ "NativeName": "हिन्दी (भारत)"
+ },
+ {
+ "LanguageTag": "hr-BA",
+ "TranslationId": "hr",
+ "TranslationGroup": "Croatian",
+ "DisplayName": "Croatian (Bosnia & Herzegovina)",
+ "NativeName": "hrvatski (Bosna i Hercegovina)"
+ },
+ {
+ "LanguageTag": "hr-HR",
+ "TranslationId": "hr",
+ "TranslationGroup": "Croatian",
+ "DisplayName": "Croatian (Croatia)",
+ "NativeName": "hrvatski (Hrvatska)"
+ },
+ {
+ "LanguageTag": "hu-HU",
+ "TranslationId": "hu",
+ "TranslationGroup": "Hungarian",
+ "DisplayName": "Hungarian (Hungary)",
+ "NativeName": "magyar (Magyarország)"
+ },
+ {
+ "LanguageTag": "id-ID",
+ "TranslationId": "id",
+ "TranslationGroup": "Indonesian",
+ "DisplayName": "Indonesian (Indonesia)",
+ "NativeName": "Indonesia (Indonesia)"
+ },
+ {
+ "LanguageTag": "is-IS",
+ "TranslationId": "is",
+ "TranslationGroup": "Icelandic",
+ "DisplayName": "Icelandic (Iceland)",
+ "NativeName": "íslenska (Ísland)"
+ },
+ {
+ "LanguageTag": "it-CH",
+ "TranslationId": "it",
+ "TranslationGroup": "Italian",
+ "DisplayName": "Italian (Switzerland)",
+ "NativeName": "italiano (Svizzera)"
+ },
+ {
+ "LanguageTag": "it-IT",
+ "TranslationId": "it",
+ "TranslationGroup": "Italian",
+ "DisplayName": "Italian (Italy)",
+ "NativeName": "italiano (Italia)"
+ },
+ {
+ "LanguageTag": "it-SM",
+ "TranslationId": "it",
+ "TranslationGroup": "Italian",
+ "DisplayName": "Italian (San Marino)",
+ "NativeName": "italiano (San Marino)"
+ },
+ {
+ "LanguageTag": "it-VA",
+ "TranslationId": "it",
+ "TranslationGroup": "Italian",
+ "DisplayName": "Italian (Vatican City)",
+ "NativeName": "italiano (Città del Vaticano)"
+ },
+ {
+ "LanguageTag": "iu-Cans-CA",
+ "TranslationId": "iu",
+ "TranslationGroup": "Inuktitut",
+ "DisplayName": "Inuktitut (Syllabics, Canada)",
+ "NativeName": "ᐃᓄᒃᑎᑐᑦ (ᑲᓇᑕᒥ)"
+ },
+ {
+ "LanguageTag": "ja-JP",
+ "TranslationId": "ja",
+ "TranslationGroup": "Japanese",
+ "DisplayName": "Japanese (Japan)",
+ "NativeName": "日本語 (日本)"
+ },
+ {
+ "LanguageTag": "kk-KZ",
+ "TranslationId": "kk",
+ "TranslationGroup": "Kazakh",
+ "DisplayName": "Kazakh (Kazakhstan)",
+ "NativeName": "қазақ тілі (Қазақстан)"
+ },
+ {
+ "LanguageTag": "kn-IN",
+ "TranslationId": "kn",
+ "TranslationGroup": "Kannada",
+ "DisplayName": "Kannada (India)",
+ "NativeName": "ಕನ್ನಡ (ಭಾರತ)"
+ },
+ {
+ "LanguageTag": "ko-KP",
+ "TranslationId": "ko",
+ "TranslationGroup": "Korean",
+ "DisplayName": "Korean (North Korea)",
+ "NativeName": "한국어 (조선민주주의인민공화국)"
+ },
+ {
+ "LanguageTag": "ko-KR",
+ "TranslationId": "ko",
+ "TranslationGroup": "Korean",
+ "DisplayName": "Korean (Korea)",
+ "NativeName": "한국어(대한민국)"
+ },
+ {
+ "LanguageTag": "ku-Arab-IQ",
+ "TranslationId": "ku",
+ "TranslationGroup": "Kurdish (Central)",
+ "DisplayName": "Central Kurdish (Iraq)",
+ "NativeName": "کوردیی ناوەڕاست (عێراق)"
+ },
+ {
+ "LanguageTag": "ku-Arab-IR",
+ "TranslationId": "ku",
+ "TranslationGroup": "Kurdish (Central)",
+ "DisplayName": "Kurdish (Perso-Arabic, Iran)",
+ "NativeName": "کوردی (ئێران)"
+ },
+ {
+ "LanguageTag": "lt-LT",
+ "TranslationId": "lt",
+ "TranslationGroup": "Lithuanian",
+ "DisplayName": "Lithuanian (Lithuania)",
+ "NativeName": "lietuvių (Lietuva)"
+ },
+ {
+ "LanguageTag": "lv-LV",
+ "TranslationId": "lv",
+ "TranslationGroup": "Latvian",
+ "DisplayName": "Latvian (Latvia)",
+ "NativeName": "latviešu (Latvija)"
+ },
+ {
+ "LanguageTag": "mg-MG",
+ "TranslationId": "mg",
+ "TranslationGroup": "Malagasy",
+ "DisplayName": "Malagasy (Madagascar)",
+ "NativeName": "Malagasy (Madagasikara)"
+ },
+ {
+ "LanguageTag": "mi-NZ",
+ "TranslationId": "mi",
+ "TranslationGroup": "Maori",
+ "DisplayName": "Maori (New Zealand)",
+ "NativeName": "te reo Māori (Aotearoa)"
+ },
+ {
+ "LanguageTag": "ml-IN",
+ "TranslationId": "ml",
+ "TranslationGroup": "Malayalam",
+ "DisplayName": "Malayalam (India)",
+ "NativeName": "മലയാളം (ഇന്ത്യ)"
+ },
+ {
+ "LanguageTag": "mr-IN",
+ "TranslationId": "mr",
+ "TranslationGroup": "Marathi",
+ "DisplayName": "Marathi (India)",
+ "NativeName": "मराठी (भारत)"
+ },
+ {
+ "LanguageTag": "ms-BN",
+ "TranslationId": "ms",
+ "TranslationGroup": "Malay",
+ "DisplayName": "Malay (Brunei)",
+ "NativeName": "Melayu (Brunei)"
+ },
+ {
+ "LanguageTag": "ms-MY",
+ "TranslationId": "ms",
+ "TranslationGroup": "Malay",
+ "DisplayName": "Malay (Malaysia)",
+ "NativeName": "Melayu (Malaysia)"
+ },
+ {
+ "LanguageTag": "ms-SG",
+ "TranslationId": "ms",
+ "TranslationGroup": "Malay",
+ "DisplayName": "Malay (Singapore)",
+ "NativeName": "Melayu (Singapura)"
+ },
+ {
+ "LanguageTag": "mt-MT",
+ "TranslationId": "mt",
+ "TranslationGroup": "Maltese",
+ "DisplayName": "Maltese (Malta)",
+ "NativeName": "Malti (Malta)"
+ },
+ {
+ "LanguageTag": "nb-NO",
+ "TranslationId": "nb",
+ "TranslationGroup": "Norwegian",
+ "DisplayName": "Norwegian Bokmål (Norway)",
+ "NativeName": "norsk bokmål (Norge)"
+ },
+ {
+ "LanguageTag": "nb-SJ",
+ "TranslationId": "nb",
+ "TranslationGroup": "Norwegian",
+ "DisplayName": "Norwegian Bokmål (Svalbard & Jan Mayen)",
+ "NativeName": "norsk bokmål (Svalbard og Jan Mayen)"
+ },
+ {
+ "LanguageTag": "nl-AW",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Aruba)",
+ "NativeName": "Nederlands (Aruba)"
+ },
+ {
+ "LanguageTag": "nl-BE",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Belgium)",
+ "NativeName": "Nederlands (België)"
+ },
+ {
+ "LanguageTag": "nl-BQ",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Bonaire, Sint Eustatius and Saba)",
+ "NativeName": "Nederlands (Bonaire, Sint Eustatius en Saba)"
+ },
+ {
+ "LanguageTag": "nl-CW",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Curaçao)",
+ "NativeName": "Nederlands (Curaçao)"
+ },
+ {
+ "LanguageTag": "nl-NL",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Netherlands)",
+ "NativeName": "Nederlands (Nederland)"
+ },
+ {
+ "LanguageTag": "nl-SR",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Suriname)",
+ "NativeName": "Nederlands (Suriname)"
+ },
+ {
+ "LanguageTag": "nl-SX",
+ "TranslationId": "nl",
+ "TranslationGroup": "Dutch",
+ "DisplayName": "Dutch (Sint Maarten)",
+ "NativeName": "Nederlands (Sint-Maarten)"
+ },
+ {
+ "LanguageTag": "or-IN",
+ "TranslationId": "or",
+ "TranslationGroup": "Odia",
+ "DisplayName": "Odia (India)",
+ "NativeName": "ଓଡ଼ିଆ (ଭାରତ)"
+ },
+ {
+ "LanguageTag": "pa-IN",
+ "TranslationId": "pa",
+ "TranslationGroup": "Punjabi",
+ "DisplayName": "Punjabi (India)",
+ "NativeName": "ਪੰਜਾਬੀ (ਭਾਰਤ)"
+ },
+ {
+ "LanguageTag": "pl-PL",
+ "TranslationId": "pl",
+ "TranslationGroup": "Polish",
+ "DisplayName": "Polish (Poland)",
+ "NativeName": "polski (Polska)"
+ },
+ {
+ "LanguageTag": "prs-AF",
+ "TranslationId": "prs",
+ "TranslationGroup": "Dari",
+ "DisplayName": "Dari (Afghanistan)",
+ "NativeName": "درى (افغانستان)"
+ },
+ {
+ "LanguageTag": "ps-AF",
+ "TranslationId": "ps",
+ "TranslationGroup": "Pashto",
+ "DisplayName": "Pashto (Afghanistan)",
+ "NativeName": "پښتو (افغانستان)"
+ },
+ {
+ "LanguageTag": "ps-PK",
+ "TranslationId": "ps",
+ "TranslationGroup": "Pashto",
+ "DisplayName": "Pashto (Pakistan)",
+ "NativeName": "پښتو (پاکستان)"
+ },
+ {
+ "LanguageTag": "pt-AO",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Angola)",
+ "NativeName": "português (Angola)"
+ },
+ {
+ "LanguageTag": "pt-BR",
+ "TranslationId": "pt",
+ "TranslationGroup": "Portuguese (Brazil)",
+ "DisplayName": "Portuguese (Brazil)",
+ "NativeName": "português (Brasil)"
+ },
+ {
+ "LanguageTag": "pt-CH",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Switzerland)",
+ "NativeName": "português (Suíça)"
+ },
+ {
+ "LanguageTag": "pt-CV",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Cabo Verde)",
+ "NativeName": "português (Cabo Verde)"
+ },
+ {
+ "LanguageTag": "pt-GQ",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Equatorial Guinea)",
+ "NativeName": "português (Guiné Equatorial)"
+ },
+ {
+ "LanguageTag": "pt-GW",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Guinea-Bissau)",
+ "NativeName": "português (Guiné-Bissau)"
+ },
+ {
+ "LanguageTag": "pt-LU",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Luxembourg)",
+ "NativeName": "português (Luxemburgo)"
+ },
+ {
+ "LanguageTag": "pt-MO",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Macao SAR)",
+ "NativeName": "português (RAE de Macau)"
+ },
+ {
+ "LanguageTag": "pt-MZ",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Mozambique)",
+ "NativeName": "português (Moçambique)"
+ },
+ {
+ "LanguageTag": "pt-PT",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Portugal)",
+ "NativeName": "português (Portugal)"
+ },
+ {
+ "LanguageTag": "pt-ST",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (São Tomé & Príncipe)",
+ "NativeName": "português (São Tomé e Príncipe)"
+ },
+ {
+ "LanguageTag": "pt-TL",
+ "TranslationId": "pt-pt",
+ "TranslationGroup": "Portuguese",
+ "DisplayName": "Portuguese (Timor-Leste)",
+ "NativeName": "português (Timor-Leste)"
+ },
+ {
+ "LanguageTag": "ro-MD",
+ "TranslationId": "ro",
+ "TranslationGroup": "Romanian",
+ "DisplayName": "Romanian (Moldova)",
+ "NativeName": "română (Republica Moldova)"
+ },
+ {
+ "LanguageTag": "ro-RO",
+ "TranslationId": "ro",
+ "TranslationGroup": "Romanian",
+ "DisplayName": "Romanian (Romania)",
+ "NativeName": "română (România)"
+ },
+ {
+ "LanguageTag": "ru-BY",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Belarus)",
+ "NativeName": "русский (Беларусь)"
+ },
+ {
+ "LanguageTag": "ru-KG",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Kyrgyzstan)",
+ "NativeName": "русский (Киргизия)"
+ },
+ {
+ "LanguageTag": "ru-KZ",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Kazakhstan)",
+ "NativeName": "русский (Казахстан)"
+ },
+ {
+ "LanguageTag": "ru-MD",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Moldova)",
+ "NativeName": "русский (Молдова)"
+ },
+ {
+ "LanguageTag": "ru-RU",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Russia)",
+ "NativeName": "русский (Россия)"
+ },
+ {
+ "LanguageTag": "ru-UA",
+ "TranslationId": "ru",
+ "TranslationGroup": "Russian",
+ "DisplayName": "Russian (Ukraine)",
+ "NativeName": "русский (Украина)"
+ },
+ {
+ "LanguageTag": "sk-SK",
+ "TranslationId": "sk",
+ "TranslationGroup": "Slovak",
+ "DisplayName": "Slovak (Slovakia)",
+ "NativeName": "slovenčina (Slovensko)"
+ },
+ {
+ "LanguageTag": "sl-SI",
+ "TranslationId": "sl",
+ "TranslationGroup": "Slovenian",
+ "DisplayName": "Slovenian (Slovenia)",
+ "NativeName": "slovenščina (Slovenija)"
+ },
+ {
+ "LanguageTag": "sr-Cyrl-BA",
+ "TranslationId": "sr-Cyrl",
+ "TranslationGroup": "Serbian (Cyrillic)",
+ "DisplayName": "Serbian (Cyrillic, Bosnia and Herzegovina)",
+ "NativeName": "српски (Босна и Херцеговина)"
+ },
+ {
+ "LanguageTag": "sr-Cyrl-ME",
+ "TranslationId": "sr-Cyrl",
+ "TranslationGroup": "Serbian (Cyrillic)",
+ "DisplayName": "Serbian (Cyrillic, Montenegro)",
+ "NativeName": "српски (Црна Гора)"
+ },
+ {
+ "LanguageTag": "sr-Cyrl-RS",
+ "TranslationId": "sr-Cyrl",
+ "TranslationGroup": "Serbian (Cyrillic)",
+ "DisplayName": "Serbian (Cyrillic, Serbia)",
+ "NativeName": "српски (Србија)"
+ },
+ {
+ "LanguageTag": "sr-Cyrl-XK",
+ "TranslationId": "sr-Cyrl",
+ "TranslationGroup": "Serbian (Cyrillic)",
+ "DisplayName": "Serbian (Cyrillic, Kosovo)",
+ "NativeName": "српски (Косово)"
+ },
+ {
+ "LanguageTag": "sr-Latn-BA",
+ "TranslationId": "sr-Latn",
+ "TranslationGroup": "Serbian (Latin)",
+ "DisplayName": "Serbian (Latin, Bosnia & Herzegovina)",
+ "NativeName": "srpski (Bosna i Hercegovina)"
+ },
+ {
+ "LanguageTag": "sr-Latn-ME",
+ "TranslationId": "sr-Latn",
+ "TranslationGroup": "Serbian (Latin)",
+ "DisplayName": "Serbian (Latin, Montenegro)",
+ "NativeName": "srpski (Crna Gora)"
+ },
+ {
+ "LanguageTag": "sr-Latn-RS",
+ "TranslationId": "sr-Latn",
+ "TranslationGroup": "Serbian (Latin)",
+ "DisplayName": "Serbian (Latin, Serbia)",
+ "NativeName": "srpski (Srbija)"
+ },
+ {
+ "LanguageTag": "sr-Latn-XK",
+ "TranslationId": "sr-Latn",
+ "TranslationGroup": "Serbian (Latin)",
+ "DisplayName": "Serbian (Latin, Kosovo)",
+ "NativeName": "srpski (Kosovo)"
+ },
+ {
+ "LanguageTag": "sv-AX",
+ "TranslationId": "sv",
+ "TranslationGroup": "Swedish",
+ "DisplayName": "Swedish (Åland Islands)",
+ "NativeName": "svenska (Åland)"
+ },
+ {
+ "LanguageTag": "sv-FI",
+ "TranslationId": "sv",
+ "TranslationGroup": "Swedish",
+ "DisplayName": "Swedish (Finland)",
+ "NativeName": "svenska (Finland)"
+ },
+ {
+ "LanguageTag": "sv-SE",
+ "TranslationId": "sv",
+ "TranslationGroup": "Swedish",
+ "DisplayName": "Swedish (Sweden)",
+ "NativeName": "svenska (Sverige)"
+ },
+ {
+ "LanguageTag": "sw-CD",
+ "TranslationId": "sw",
+ "TranslationGroup": "Swahili",
+ "DisplayName": "Kiswahili (Congo DRC)",
+ "NativeName": "Kiswahili (Jamhuri ya Kidemokrasia ya Kongo)"
+ },
+ {
+ "LanguageTag": "sw-KE",
+ "TranslationId": "sw",
+ "TranslationGroup": "Swahili",
+ "DisplayName": "Kiswahili (Kenya)",
+ "NativeName": "Kiswahili (Kenya)"
+ },
+ {
+ "LanguageTag": "sw-TZ",
+ "TranslationId": "sw",
+ "TranslationGroup": "Swahili",
+ "DisplayName": "Kiswahili (Tanzania)",
+ "NativeName": "Kiswahili (Tanzania)"
+ },
+ {
+ "LanguageTag": "sw-UG",
+ "TranslationId": "sw",
+ "TranslationGroup": "Swahili",
+ "DisplayName": "Kiswahili (Uganda)",
+ "NativeName": "Kiswahili (Uganda)"
+ },
+ {
+ "LanguageTag": "ta-IN",
+ "TranslationId": "ta",
+ "TranslationGroup": "Tamil",
+ "DisplayName": "Tamil (India)",
+ "NativeName": "தமிழ் (இந்தியா)"
+ },
+ {
+ "LanguageTag": "ta-LK",
+ "TranslationId": "ta",
+ "TranslationGroup": "Tamil",
+ "DisplayName": "Tamil (Sri Lanka)",
+ "NativeName": "தமிழ் (இலங்கை)"
+ },
+ {
+ "LanguageTag": "ta-MY",
+ "TranslationId": "ta",
+ "TranslationGroup": "Tamil",
+ "DisplayName": "Tamil (Malaysia)",
+ "NativeName": "தமிழ் (மலேசியா)"
+ },
+ {
+ "LanguageTag": "ta-SG",
+ "TranslationId": "ta",
+ "TranslationGroup": "Tamil",
+ "DisplayName": "Tamil (Singapore)",
+ "NativeName": "தமிழ் (சிங்கப்பூர்)"
+ },
+ {
+ "LanguageTag": "te-IN",
+ "TranslationId": "te",
+ "TranslationGroup": "Telugu",
+ "DisplayName": "Telugu (India)",
+ "NativeName": "తెలుగు (భారతదేశం)"
+ },
+ {
+ "LanguageTag": "th-TH",
+ "TranslationId": "th",
+ "TranslationGroup": "Thai",
+ "DisplayName": "Thai (Thailand)",
+ "NativeName": "ไทย (ไทย)"
+ },
+ {
+ "LanguageTag": "to-TO",
+ "TranslationId": "to",
+ "TranslationGroup": "Tongan",
+ "DisplayName": "Tongan (Tonga)",
+ "NativeName": "lea fakatonga (Tonga)"
+ },
+ {
+ "LanguageTag": "tr-CY",
+ "TranslationId": "tr",
+ "TranslationGroup": "Turkish",
+ "DisplayName": "Turkish (Cyprus)",
+ "NativeName": "Türkçe (Kıbrıs)"
+ },
+ {
+ "LanguageTag": "tr-TR",
+ "TranslationId": "tr",
+ "TranslationGroup": "Turkish",
+ "DisplayName": "Turkish (Turkey)",
+ "NativeName": "Türkçe (Türkiye)"
+ },
+ {
+ "LanguageTag": "uk-UA",
+ "TranslationId": "uk",
+ "TranslationGroup": "Ukrainian",
+ "DisplayName": "Ukrainian (Ukraine)",
+ "NativeName": "українська (Україна)"
+ },
+ {
+ "LanguageTag": "ur-IN",
+ "TranslationId": "ur",
+ "TranslationGroup": "Urdu",
+ "DisplayName": "Urdu (India)",
+ "NativeName": "اردو (بھارت)"
+ },
+ {
+ "LanguageTag": "ur-PK",
+ "TranslationId": "ur",
+ "TranslationGroup": "Urdu",
+ "DisplayName": "Urdu (Pakistan)",
+ "NativeName": "اُردو (پاکستان)"
+ },
+ {
+ "LanguageTag": "vi-VN",
+ "TranslationId": "vi",
+ "TranslationGroup": "Vietnamese",
+ "DisplayName": "Vietnamese (Vietnam)",
+ "NativeName": "Tiếng Việt (Việt Nam)"
+ },
+ {
+ "LanguageTag": "zh-CN",
+ "TranslationId": "zh-Hans",
+ "TranslationGroup": "Chinese (Simplified)",
+ "DisplayName": "Chinese (Simplified, China)",
+ "NativeName": "中文(中国)"
+ },
+ {
+ "LanguageTag": "zh-Hans-HK",
+ "TranslationId": "zh-Hans",
+ "TranslationGroup": "Chinese (Simplified)",
+ "DisplayName": "Chinese (Simplified Han, Hong Kong SAR)",
+ "NativeName": "中文 (香港特别行政区)"
+ },
+ {
+ "LanguageTag": "zh-Hans-MO",
+ "TranslationId": "zh-Hans",
+ "TranslationGroup": "Chinese (Simplified)",
+ "DisplayName": "Chinese (Simplified Han, Macao SAR)",
+ "NativeName": "中文 (澳门特别行政区)"
+ },
+ {
+ "LanguageTag": "zh-HK",
+ "TranslationId": "zh-Hant",
+ "TranslationGroup": "Chinese (Traditional)",
+ "DisplayName": "Chinese (Traditional, Hong Kong SAR)",
+ "NativeName": "中文(香港特別行政區)"
+ },
+ {
+ "LanguageTag": "zh-MO",
+ "TranslationId": "zh-Hant",
+ "TranslationGroup": "Chinese (Traditional)",
+ "DisplayName": "Chinese (Traditional, Macao SAR)",
+ "NativeName": "中文(澳門特別行政區)"
+ },
+ {
+ "LanguageTag": "zh-SG",
+ "TranslationId": "zh-Hans",
+ "TranslationGroup": "Chinese (Simplified)",
+ "DisplayName": "Chinese (Simplified, Singapore)",
+ "NativeName": "中文(新加坡)"
+ },
+ {
+ "LanguageTag": "zh-TW",
+ "TranslationId": "zh-Hant",
+ "TranslationGroup": "Chinese (Traditional)",
+ "DisplayName": "Chinese (Traditional, Taiwan)",
+ "NativeName": "中文(台灣)"
+ }
+]
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Translations/Language.cs b/MetadataTranslator/Metadata Translator/Translations/Language.cs
new file mode 100644
index 0000000..9cde8a9
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Translations/Language.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class Language : INotifyPropertyChanged
+ {
+ #region INotifyPropertyChanged implementation
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void NotifyPropertyChanged(string propertyName = null)
+ {
+ if (PropertyChanged != null)
+ PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ #endregion
+
+ public string LanguageTag { get; set; }
+ public string TranslationId { get; set; }
+ public string TranslationGroup { get; set; }
+ public string DisplayName { get; set; }
+ public string NativeName { get; set; }
+
+ private bool isSelected = false;
+ public bool IsSelected
+ {
+ get => isSelected;
+ set
+ {
+ isSelected = value;
+ NotifyPropertyChanged("IsSelected");
+ }
+ }
+
+ public bool IsModelDefault { get; set; }
+ public bool IsNotModelDefault { get => !IsModelDefault; }
+ }
+}
\ No newline at end of file
diff --git a/MetadataTranslator/Metadata Translator/Translations/Translation.cs b/MetadataTranslator/Metadata Translator/Translations/Translation.cs
new file mode 100644
index 0000000..78adcf0
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Translations/Translation.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class Translation
+ {
+ public string text { get; set; }
+ public string to { get; set; }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Translations/TranslationGroup.cs b/MetadataTranslator/Metadata Translator/Translations/TranslationGroup.cs
new file mode 100644
index 0000000..73102b3
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Translations/TranslationGroup.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class TranslationGroup
+ {
+ public string Name { get; set; }
+ public string Tag { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is TranslationGroup comparewith)
+ {
+ return Name == comparewith.Name && Tag == comparewith.Tag;
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return new { Tag, Name }.GetHashCode();
+ }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Translations/TranslationResult.cs b/MetadataTranslator/Metadata Translator/Translations/TranslationResult.cs
new file mode 100644
index 0000000..0e17b4b
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Translations/TranslationResult.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Metadata_Translator
+{
+ public class TranslationResult
+ {
+ public List translations { get; set; }
+ }
+}
diff --git a/MetadataTranslator/Metadata Translator/Translations/TranslatorService.cs b/MetadataTranslator/Metadata Translator/Translations/TranslatorService.cs
new file mode 100644
index 0000000..a109c0c
--- /dev/null
+++ b/MetadataTranslator/Metadata Translator/Translations/TranslatorService.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web.Script.Serialization;
+
+namespace Metadata_Translator
+{
+ public class TranslatorService
+ {
+ List Languages { get; set; }
+ string SourceLanguage { get; set; }
+ string SubscriptionKey { get; set; }
+ string Endpoint { get; set; }
+ string Location { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public TranslatorService(List languages, string sourceLanguage, string subscriptionKey, string endpoint, string location)
+ {
+ Languages = languages;
+ SourceLanguage = sourceLanguage;
+
+ SubscriptionKey = subscriptionKey;
+ Endpoint = endpoint;
+ Location = location;
+ }
+
+ public void Translate(List dataRows, bool replaceExistingTranslations)
+ {
+ /// No languages, or only the one source language? Nothing to translate!
+ ///
+ if (Languages == null || Languages.Count < 2) return;
+
+ /// Get the target languages (i.e. not the SourceLanguage).
+ ///
+ List targetLanguages = Languages.Where(l => !l.LanguageTag.Equals(SourceLanguage)).ToList();
+
+ /// Filter down the data rows to those with values in the source language.
+ ///
+ List filteredRows = dataRows.Where(dr => !string.IsNullOrEmpty(dr.GetValue(SourceLanguage)))?.ToList();
+
+ /// No rows? Nothing to translate!
+ ///
+ if (filteredRows == null || filteredRows.Count == 0) return;
+
+ /// Iterate over the TranslationGroups, all languages within the same group
+ /// share the same translation id.
+ ///
+ foreach(string id in targetLanguages.Select(tl => tl.TranslationId).Distinct())
+ {
+ Translate(filteredRows, targetLanguages.Where(tl => tl.TranslationId.Equals(id)), id, replaceExistingTranslations);
+ }
+ }
+
+ private void Translate(List dataRows, IEnumerable targetLanguages, string translationId, bool replaceExistingTranslations)
+ {
+ List rowsToTranslate = new List();
+
+ /// Don't replace existing translations?
+ /// Filter down the data rows to those that are empty for at least one of the target languages.
+ ///
+ if (!replaceExistingTranslations)
+ {
+ foreach(Language language in targetLanguages)
+ {
+ rowsToTranslate.AddRange(dataRows.Where(dr => string.IsNullOrEmpty(dr.GetValue(language.LanguageTag))));
+ }
+ rowsToTranslate = rowsToTranslate.Distinct()?.ToList();
+ }
+ else
+ {
+ /// Otherwise translate all data rows.
+ ///
+ rowsToTranslate = dataRows;
+ }
+
+ /// Now translate the source strings recursively.
+ ///
+ Translate(rowsToTranslate, targetLanguages, translationId, replaceExistingTranslations, 0);
+ }
+
+ private void Translate(List dataRows, IEnumerable targetLanguages, string translationId, bool replaceExistingTranslations, int iterationId)
+ {
+ int maxBatchSize = 100;
+ int batchStart = maxBatchSize * iterationId;
+
+ /// Check if all strings have been translated.
+ ///
+ if (dataRows.Count <= batchStart) return;
+
+ /// Assemble a translation batch of up to maxBatchSize.
+ ///
+ maxBatchSize = (dataRows.Count - batchStart) < maxBatchSize? dataRows.Count - batchStart : maxBatchSize;
+ List