diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6d570d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+#################
+## Transifex
+#################
+
+transifexAuth.json
\ No newline at end of file
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..1fdf69a
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javascript/lang/cs.js b/javascript/lang/cs.js
new file mode 100644
index 0000000..3a52c4b
--- /dev/null
+++ b/javascript/lang/cs.js
@@ -0,0 +1,13 @@
+// DO NOT MODIFY. Generated by build task.
+// Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
+if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
+ if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
+} else {
+ ss.i18n.addDictionary('cs', {
+ "GridFieldBulkTools.FINISH_CONFIRM": "Máte neuložené změny. Pokud budete pokračovat neuložená data budou nenávratně ztracena.\n\nOpravdu chcete pokračovat?",
+ "GridFieldBulkTools.EDIT_CHANGED": "Změněno",
+ "GridFieldBulkTools.EDIT_UPDATED": "Uloženo",
+ "GridFieldBulkManager.BULKACTION_EMPTY_SELECT": "Musíte vybrat alespoň jednu položku.",
+ "GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION": "Data budou nenávratně ztracena. Opravdu chcete pokračovat?"
+});
+}
\ No newline at end of file
diff --git a/javascript/lang/cs_CZ.js b/javascript/lang/cs_CZ.js
deleted file mode 100644
index ffc83a7..0000000
--- a/javascript/lang/cs_CZ.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
- console.error('Class ss.i18n not defined');
-} else {
- ss.i18n.addDictionary('cs_CZ', {
- 'GridFieldBulkTools.FINISH_CONFIRM': "Máte neuložené změny. Pokud budete pokračovat neuložená data budou nenávratně ztracena.\n\nOpravdu chcete pokračovat?",
- 'GridFieldBulkTools.EDIT_CHANGED': 'Změněno',
- 'GridFieldBulkTools.EDIT_UPDATED': 'Uloženo',
- 'GridFieldBulkManager.BULKACTION_EMPTY_SELECT': 'Musíte vybrat alespoň jednu položku.',
- 'GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION': 'Data budou nenávratně ztracena. Opravdu chcete pokračovat?'
- });
-}
diff --git a/javascript/lang/de.js b/javascript/lang/de.js
new file mode 100644
index 0000000..e0a5342
--- /dev/null
+++ b/javascript/lang/de.js
@@ -0,0 +1,13 @@
+// DO NOT MODIFY. Generated by build task.
+// Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
+if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
+ if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
+} else {
+ ss.i18n.addDictionary('de', {
+ "GridFieldBulkTools.FINISH_CONFIRM": "Ihre Änderungen sind nicht gespeichert. Wenn sie fortfahren gehen diese Daten verloren.\n\nMöchten Sie fortfahren?",
+ "GridFieldBulkTools.EDIT_CHANGED": "Geändert",
+ "GridFieldBulkTools.EDIT_UPDATED": "Gespeichert",
+ "GridFieldBulkManager.BULKACTION_EMPTY_SELECT": "Sie müssen mindestens ein Element auswählen",
+ "GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION": "Wollen Sie dieses Element wirklich unwiderruflich löschen?"
+});
+}
\ No newline at end of file
diff --git a/javascript/lang/de_DE.js b/javascript/lang/de_DE.js
deleted file mode 100644
index af33277..0000000
--- a/javascript/lang/de_DE.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
- console.error('Class ss.i18n not defined');
-} else {
- ss.i18n.addDictionary('de_DE', {
- 'GridFieldBulkTools.FINISH_CONFIRM': "Ihre Änderungen sind nicht gespeichert. Wenn sie fortfahren gehen diese Daten verloren.\n\nMöchten Sie fortfahren?",
- 'GridFieldBulkTools.EDIT_CHANGED': 'Geändert',
- 'GridFieldBulkTools.EDIT_UPDATED': 'Gespeichert',
- 'GridFieldBulkManager.BULKACTION_EMPTY_SELECT': 'Sie müssen mindestens ein Element auswählen',
- 'GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION': 'Wollen Sie dieses Element wirklich unwiderruflich löschen?'
- });
-}
diff --git a/javascript/lang/en.js b/javascript/lang/en.js
new file mode 100644
index 0000000..2af5028
--- /dev/null
+++ b/javascript/lang/en.js
@@ -0,0 +1,13 @@
+// DO NOT MODIFY. Generated by build task.
+// Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
+if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
+ if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
+} else {
+ ss.i18n.addDictionary('en', {
+ "GridFieldBulkTools.FINISH_CONFIRM": "You have unsaved changes. Continuing will loose all unsaved data.\n\nDo your really want to continue?",
+ "GridFieldBulkTools.EDIT_CHANGED": "Modified",
+ "GridFieldBulkTools.EDIT_UPDATED": "Saved",
+ "GridFieldBulkManager.BULKACTION_EMPTY_SELECT": "You must select at least one record.",
+ "GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION": "The data will be lost permanently. Do you want to continue?"
+});
+}
\ No newline at end of file
diff --git a/javascript/lang/en_US.js b/javascript/lang/en_US.js
deleted file mode 100644
index 99221bd..0000000
--- a/javascript/lang/en_US.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
- console.error('Class ss.i18n not defined');
-} else {
- ss.i18n.addDictionary('en_US', {
- 'GridFieldBulkTools.FINISH_CONFIRM': "You have unsaved changes. Continuing will loose all unsaved data.\n\nDo your really want to continue?",
- 'GridFieldBulkTools.EDIT_CHANGED': 'Modified',
- 'GridFieldBulkTools.EDIT_UPDATED': 'Saved',
- 'GridFieldBulkManager.BULKACTION_EMPTY_SELECT': 'You must select at least one record.',
- 'GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION': 'The data will be lost permanently. Do you want to continue?'
- });
-}
diff --git a/javascript/lang/fr.js b/javascript/lang/fr.js
new file mode 100644
index 0000000..6823505
--- /dev/null
+++ b/javascript/lang/fr.js
@@ -0,0 +1,13 @@
+// DO NOT MODIFY. Generated by build task.
+// Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
+if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
+ if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
+} else {
+ ss.i18n.addDictionary('fr', {
+ "GridFieldBulkTools.FINISH_CONFIRM": "Vous avez des changements non enregistrés. En continuant vous allez perdre toutes vos données non enregistrées.\n\nVoulez-vous vraiment continuer?",
+ "GridFieldBulkTools.EDIT_CHANGED": "Changé",
+ "GridFieldBulkTools.EDIT_UPDATED": "Enregisté",
+ "GridFieldBulkManager.BULKACTION_EMPTY_SELECT": "Vous devez séléctionner au moins un élément.",
+ "GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION": "Vos données seront perdues définitivement. Voulez-vous continuer?"
+});
+}
\ No newline at end of file
diff --git a/javascript/lang/fr_FR.js b/javascript/lang/fr_FR.js
deleted file mode 100644
index 0e31c8c..0000000
--- a/javascript/lang/fr_FR.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
- console.error('Class ss.i18n not defined');
-} else {
- ss.i18n.addDictionary('fr_FR', {
- 'GridFieldBulkTools.FINISH_CONFIRM': "Vous avez des changements non enregistrés. En continuant vous allez perdre toutes vos données non enregistrées.\n\nVoulez-vous vraiment continuer?",
- 'GridFieldBulkTools.EDIT_CHANGED': 'Changé',
- 'GridFieldBulkTools.EDIT_UPDATED': 'Enregisté',
- 'GridFieldBulkManager.BULKACTION_EMPTY_SELECT': 'Vous devez séléctionner au moins un élément.',
- 'GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION': 'Vos données seront perdues définitivement. Voulez-vous continuer?'
- });
-}
diff --git a/javascript/lang/nl.js b/javascript/lang/nl.js
new file mode 100644
index 0000000..82b2b84
--- /dev/null
+++ b/javascript/lang/nl.js
@@ -0,0 +1,13 @@
+// DO NOT MODIFY. Generated by build task.
+// Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
+if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
+ if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
+} else {
+ ss.i18n.addDictionary('nl', {
+ "GridFieldBulkTools.FINISH_CONFIRM": "Er zijn niet-opgeslagen wijzigingen.\n\nDoorgaan zal al deze niet-opgeslagen wijzigingen vergeten.\n\nWeet je zeker dat je de pagina wilt verlaten?",
+ "GridFieldBulkTools.EDIT_CHANGED": "Aangepast",
+ "GridFieldBulkTools.EDIT_UPDATED": "Opgeslagen",
+ "GridFieldBulkManager.BULKACTION_EMPTY_SELECT": "U moet minstens een item te selecteren.",
+ "GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION": "De gegevens zullen permanent verloren. Weet je zeker dat je de pagina wilt verlaten?"
+});
+}
\ No newline at end of file
diff --git a/javascript/lang/nl_NL.js b/javascript/lang/nl_NL.js
deleted file mode 100644
index 3926d08..0000000
--- a/javascript/lang/nl_NL.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
- console.error('Class ss.i18n niet gevonden of niet gedefinieerd');
-} else {
- ss.i18n.addDictionary('nl_NL', {
- 'GridFieldBulkTools.FINISH_CONFIRM': "Er zijn niet-opgeslagen wijzigingen.\n\nDoorgaan zal al deze niet-opgeslagen wijzigingen vergeten.\n\nWeet je zeker dat je de pagina wilt verlaten?",
- 'GridFieldBulkTools.EDIT_CHANGED': 'Aangepast',
- 'GridFieldBulkTools.EDIT_UPDATED': 'Opgeslagen',
- 'GridFieldBulkManager.BULKACTION_EMPTY_SELECT': 'U moet minstens een item te selecteren.',
- 'GridFieldBulkManager.CONFIRM_DESTRUCTIVE_ACTION': 'De gegevens zullen permanent verloren. Weet je zeker dat je de pagina wilt verlaten?'
- });
-}
\ No newline at end of file
diff --git a/lang/cs.yml b/lang/cs.yml
index ef90a39..32268e3 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -1,3 +1,5 @@
+# DO NOT MODIFY. Generated by build task.
+# Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
cs:
GridFieldBulkTools:
BULK_UPLOAD_BTN_LABEL: Hromadně nahrát
@@ -10,4 +12,4 @@ cs:
ACTION_BTN_LABEL: Provést
SELECT_ALL_LABEL: Vybrat vše
GridFieldBulkManager:
- CANCEL_BTN_LABEL: Storno
+ CANCEL_BTN_LABEL: Storno
\ No newline at end of file
diff --git a/lang/de.yml b/lang/de.yml
index 85b9bf7..236f3fe 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -1,3 +1,5 @@
+# DO NOT MODIFY. Generated by build task.
+# Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
de:
GridFieldBulkTools:
BULK_UPLOAD_BTN_LABEL: Bulk Upload
diff --git a/lang/en.yml b/lang/en.yml
index f23981a..239e09d 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -1,3 +1,5 @@
+# DO NOT MODIFY. Generated by build task.
+# Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
en:
GridFieldBulkTools:
BULK_UPLOAD_BTN_LABEL: Bulk Upload
diff --git a/lang/fr.yml b/lang/fr.yml
index 55e6c60..36eda0e 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -1,3 +1,5 @@
+# DO NOT MODIFY. Generated by build task.
+# Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
fr:
GridFieldBulkTools:
BULK_UPLOAD_BTN_LABEL: Upload groupé
diff --git a/lang/nl.yml b/lang/nl.yml
index e3afdeb..fb431ae 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -1,3 +1,5 @@
+# DO NOT MODIFY. Generated by build task.
+# Contribute here: https://www.transifex.com/projects/p/gridfieldbulkeditingtools/
nl:
GridFieldBulkTools:
BULK_UPLOAD_BTN_LABEL: Bulk Upload
@@ -10,4 +12,4 @@ nl:
ACTION_BTN_LABEL: Gaan
SELECT_ALL_LABEL: Selecteer alles
GridFieldBulkManager:
- CANCEL_BTN_LABEL: Annuleren
+ CANCEL_BTN_LABEL: Annuleren
\ No newline at end of file
diff --git a/tasks/BuildTransifexTranslations.php b/tasks/BuildTransifexTranslations.php
new file mode 100644
index 0000000..e5e6e56
--- /dev/null
+++ b/tasks/BuildTransifexTranslations.php
@@ -0,0 +1,292 @@
+txapi = $txapi;
+ }
+
+ public function settxproject($txproject)
+ {
+ $this->txproject = $txproject;
+ }
+
+ /**
+ * Task init
+ */
+ public function init()
+ {
+ $root = realpath(__DIR__ . DIRECTORY_SEPARATOR . '..');
+ $authFile = $root . DIRECTORY_SEPARATOR . $this->txAuthFile;
+
+ if ( file_exists($authFile) )
+ {
+ $txAuthData = file_get_contents($authFile);
+ $txAuthData = json_decode($txAuthData);
+ if ( $txAuthData->username && $txAuthData->password )
+ {
+ $this->txAuth = $txAuthData;
+ }
+ else{
+ throw new BuildException("Transifex credentials malformat. Check your $authFile for 'username' and 'password' keys.");
+ }
+ }
+ else{
+ throw new BuildException("Transifex credentials not found. $authFile missing.");
+ }
+
+ $this->root = $root;
+ $this->jsDir = $root . $this->jsDir;
+ $this->ymlDir = $root . $this->ymlDir;
+ }
+
+ /**
+ * Let's get to buisness...
+ */
+ public function main()
+ {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ curl_setopt($ch, CURLOPT_USERPWD, $this->txAuth->username . ":" . $this->txAuth->password);
+
+ // get resources
+ $url = $this->txapi.'/project/'.$this->txproject.'/resources/';
+ curl_setopt($ch, CURLOPT_URL, $url);
+ $resources = curl_exec($ch);
+
+ if ( !$resources )
+ {
+ throw new BuildException("Cannot fetch resources");
+ }
+ else{
+ $resources = json_decode($resources);
+ }
+
+ // get langs
+ $url = $this->txapi.'/project/'.$this->txproject.'/languages/';
+ curl_setopt($ch, CURLOPT_URL, $url);
+ $languages = curl_exec($ch);
+
+ if ( !$languages )
+ {
+ throw new BuildException("Cannot fetch languages");
+ }
+ else{
+ $languages = json_decode($languages);
+ }
+
+ // clear existing translation files and/or setup folders
+ $this->resetTranslations();
+
+ // add source_language_code to languages list
+ $sourceLangs = array();
+ foreach ($resources as $resource)
+ {
+ $lang = new StdClass();
+ $locale = $resource->source_language_code;
+ $lang->language_code = $locale;
+ if ( !array_key_exists($locale, $sourceLangs) )
+ {
+ $sourceLangs[$locale] = $lang;
+ }
+ }
+ $sourceLangs = array_values($sourceLangs);
+ $languages = array_merge($languages, $sourceLangs);
+
+ // get each resource translations
+ foreach ($resources as $resource)
+ {
+ foreach ($languages as $language)
+ {
+ $url = $this->txapi.'/project/'.$this->txproject.'/resource/'.$resource->slug.'/translation/'.$language->language_code;
+ curl_setopt($ch, CURLOPT_URL, $url);
+ $data = curl_exec($ch);
+ if ( $data )
+ {
+ $this->saveTranslation($resource->slug, $language->language_code, $data);
+ }
+ }
+ }
+
+ curl_close($ch);
+ }
+
+ /**
+ * Clear any existing translation files
+ * and create directory structure if needed
+ */
+ private function resetTranslations()
+ {
+ if ( file_exists($this->jsDir) )
+ {
+ echo "Clearing js translations...\n";
+ $iterator = new GlobIterator($this->jsDir . DIRECTORY_SEPARATOR . '*.js');
+ foreach ($iterator as $fileInfo)
+ {
+ if ( $fileInfo->isFile() )
+ {
+ $del = unlink($fileInfo->getRealPath());
+ }
+ }
+ }
+
+ if ( file_exists($this->ymlDir) )
+ {
+ echo "Clearing yml translations...\n";
+ $iterator = new GlobIterator($this->ymlDir . DIRECTORY_SEPARATOR . '*.yml');
+ foreach ($iterator as $fileInfo)
+ {
+ if ( $fileInfo->isFile() )
+ {
+ $del = unlink($fileInfo->getRealPath());
+ }
+ }
+ }
+
+ if ( !file_exists($this->jsDir) )
+ {
+ echo "Creating js folders...\n";
+ mkdir($this->jsDir);
+ }
+
+ if ( !file_exists($this->ymlDir) )
+ {
+ echo "Creating yml folders...\n";
+ mkdir($this->ymlDir);
+ }
+ }
+
+ /**
+ * Hook that detect the translation type via resource slug
+ * and call corect saving function with data
+ * @param string $resource Transifex resrouce slug
+ * @param string $locale Transifex locale
+ * @param string $data Raw Transifex translation data
+ */
+ private function saveTranslation($resource, $locale, $data)
+ {
+ if ( !$resource || !$locale || !$data )
+ {
+ return;
+ }
+
+ $data = json_decode($data);
+ $translation = rtrim($data->content);
+
+ switch ($resource)
+ {
+ case 'js':
+ $this->saveJSTranslation($locale, $translation);
+ break;
+
+ case 'yml':
+ $this->saveYMLTranslation($locale, $translation);
+ break;
+ }
+ }
+
+ /**
+ * Save a JS translation file
+ * Uses JSTemplate to fit with SilverStripe requirements
+ * @param string $locale Locale code
+ * @param string $json JSON translation key:value
+ */
+ private function saveJSTranslation($locale, $json)
+ {
+ echo "Saving $locale.js\n";
+ file_put_contents(
+ $this->jsDir . DIRECTORY_SEPARATOR . $locale . '.js',
+ $this->getBanner('js') .
+ str_replace(
+ array(
+ '%TRANSLATIONS%',
+ '%LOCALE%'
+ ),
+ array(
+ $json,
+ $locale
+ ),
+ $this->getJSTemplate()
+ )
+ );
+ }
+
+ /**
+ * Save a YML translation file
+ * @param string $locale Locale code
+ * @param string $yml YML translation
+ */
+ public function saveYMLTranslation($locale, $yml)
+ {
+ echo "Saving $locale.yml\n";
+ file_put_contents(
+ $this->ymlDir . DIRECTORY_SEPARATOR . $locale . '.yml',
+ $this->getBanner('yml') . $yml
+ );
+ }
+
+ /**
+ * Return the commented file banner
+ * @param string $type File type e.g js
+ * @return string The commented file banner
+ */
+ private function getBanner($type)
+ {
+ switch ( strtolower($type) )
+ {
+ case 'yml':
+ $comment = "#";
+ break;
+
+ default:
+ $comment = "//";
+ break;
+ }
+
+ $banner = <<