diff --git a/core/db.sqlite3 b/core/db.sqlite3 index e51d55a..60c13c5 100644 Binary files a/core/db.sqlite3 and b/core/db.sqlite3 differ diff --git a/core/i18nilize/services/translation_processor.py b/core/i18nilize/services/translation_processor.py index 405440c..6c8d60b 100644 --- a/core/i18nilize/services/translation_processor.py +++ b/core/i18nilize/services/translation_processor.py @@ -156,3 +156,15 @@ def bulk_update_translations(token, updated_translations): except Exception as e: print(e) return False, 0 + +def get_translations_by_language(language, token): + """ + Return all translations for the given language as a dictionary. + """ + translations = Translation.objects.filter(language=language, token=token) + + translations_dict = { + translation.original_word: translation.translated_word + for translation in translations + } + return translations_dict \ No newline at end of file diff --git a/core/i18nilize/tests.py b/core/i18nilize/tests.py index c973724..f0caedb 100644 --- a/core/i18nilize/tests.py +++ b/core/i18nilize/tests.py @@ -2,7 +2,7 @@ from rest_framework import status from rest_framework.test import APITestCase from .models import Token, Translation -from .services.translation_processor import bulk_create_translations, bulk_update_translations +from .services.translation_processor import bulk_create_translations, bulk_update_translations, get_translations_by_language class TokenViewTests(APITestCase): @@ -327,6 +327,62 @@ def test_update_translations_rollback(self): translations = Translation.objects.all() self.assertEqual(len(translations), 0) + def test_get_translations_no_translations_found(self): + translations_data = { + 'translations': [ + { + 'language': 'spanish', + 'hello': 'hola' + } + ] + } + query_params = { + 'language': 'french' + } + + headers = { + 'HTTP_Token': self.TEST_TOKEN + } + + # create spanish translations + response = self.client.post(reverse('process-translations'), translations_data, **headers, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # fetch french translations + response = self.client.get(reverse('process-translations'), **headers, query_params=query_params) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual(response.data['error'], 'No translations found for french.') + + def test_get_translations_by_language(self): + translations_data = { + 'translations': [ + { + 'language': 'spanish', + 'hello': 'hola' + } + ] + } + query_params = { + 'language': 'spanish' + } + + expected_response_data = { + 'hello': 'hola' + } + + headers = { + 'HTTP_Token': self.TEST_TOKEN + } + + # create spanish translations + response = self.client.post(reverse('process-translations'), translations_data, **headers, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # fetch spanish translations + response = self.client.get(reverse('process-translations'), **headers, query_params=query_params) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data, expected_response_data) + class TranslationViewTests(APITestCase): diff --git a/core/i18nilize/views.py b/core/i18nilize/views.py index ccaae60..8adc567 100644 --- a/core/i18nilize/views.py +++ b/core/i18nilize/views.py @@ -134,6 +134,23 @@ def patch(self, request): status=status.HTTP_201_CREATED ) + @require_valid_token + def get(self, request): + """ + Fetch translations for a given language. + """ + token = request.token + language = request.query_params.get('language') + + translations = tp.get_translations_by_language(language, token) + if not translations: + return Response( + {'error': f'No translations found for {language}.'}, + status=status.HTTP_404_NOT_FOUND + ) + + return Response(translations, status=status.HTTP_200_OK) + class TranslationView(APIView): """ CRUD endpoint to read single translation diff --git a/core/requirements.txt b/core/requirements.txt index ae0dc58..5254a41 100644 --- a/core/requirements.txt +++ b/core/requirements.txt @@ -1,4 +1,9 @@ asgiref==3.8.1 +certifi==2024.8.30 +charset-normalizer==3.4.0 Django==5.1.1 djangorestframework==3.15.2 +idna==3.10 +requests==2.32.3 sqlparse==0.5.1 +urllib3==2.2.3 diff --git a/i18nilize/src/internationalize/__pycache__/helpers.cpython-311.pyc b/i18nilize/src/internationalize/__pycache__/helpers.cpython-311.pyc index 38dda70..6781682 100644 Binary files a/i18nilize/src/internationalize/__pycache__/helpers.cpython-311.pyc and b/i18nilize/src/internationalize/__pycache__/helpers.cpython-311.pyc differ diff --git a/i18nilize/src/internationalize/helpers.py b/i18nilize/src/internationalize/helpers.py index adee5bc..948c72e 100644 --- a/i18nilize/src/internationalize/helpers.py +++ b/i18nilize/src/internationalize/helpers.py @@ -1,4 +1,6 @@ import json +import os +import requests # Function to parse json file, given its path def get_json(file_path): @@ -28,31 +30,29 @@ def get_token(file_path): # Input: a JSON object # Output: None, but creates a local JSON file containing the object -def create_json(json_object): - with open("src/internationalize/jsonFile/translations.json", "w") as outfile: +def create_json(json_object, language): + base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__))) + file_path = os.path.join(base_dir, 'languages', f'{language}.json') + with open(file_path, 'w') as outfile: outfile.write(json_object) -# Input: None (for now) +# Input: language # Output: None, but creates a local JSON file containing translations -def generate_file(): - file_content = { - "Token": "85124f79-0829-4b80-8b5c-d52700d86e46", - "translations" : [{ - "language": "French", - "hello": "bonjour", - "No": "Non", - "Why": "pourquoi", - }, - { - "language": "Spanish", - "hello": "Hola", - }, - ] - } +def generate_file(language, token): + url = 'http://localhost:8000/api/translations' + params = {'language': language} + headers = {'token': token} + response = requests.get(url, params=params, headers=headers) + if response.status_code != 200: + print(f'Error: {response.status_code}.', response.json()['error']) + return + + file_content = response.json() + # transforms the dictionary object above into a JSON object json_object = json.dumps(file_content, indent=4) - create_json(json_object) + create_json(json_object, language) # make hashmap from translations def make_translation_map(data): diff --git a/i18nilize/src/internationalize/jsonFile/translations.json b/i18nilize/src/internationalize/jsonFile/translations.json deleted file mode 100644 index 9a4373a..0000000 --- a/i18nilize/src/internationalize/jsonFile/translations.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Token": "85124f79-0829-4b80-8b5c-d52700d86e46", - "translations": [ - { - "language": "French", - "hello": "bonjour", - "No": "Non", - "Why": "pourquoi" - }, - { - "language": "Spanish", - "hello": "Hola" - } - ] -} \ No newline at end of file diff --git a/i18nilize/src/internationalize/languages/french.json b/i18nilize/src/internationalize/languages/french.json new file mode 100644 index 0000000..78b6885 --- /dev/null +++ b/i18nilize/src/internationalize/languages/french.json @@ -0,0 +1,4 @@ +{ + "thanks": "merci", + "hello": "bonjour" +} \ No newline at end of file diff --git a/i18nilize/src/internationalize/languages/spanish.json b/i18nilize/src/internationalize/languages/spanish.json new file mode 100644 index 0000000..11336ed --- /dev/null +++ b/i18nilize/src/internationalize/languages/spanish.json @@ -0,0 +1,4 @@ +{ + "hello": "hola", + "thanks": "gracias" +} \ No newline at end of file diff --git a/i18nilize/tests/test_generate_file.py b/i18nilize/tests/test_generate_file.py index 0ba59a7..d0b8945 100644 --- a/i18nilize/tests/test_generate_file.py +++ b/i18nilize/tests/test_generate_file.py @@ -1,29 +1,45 @@ import unittest +from unittest.mock import patch, Mock import json -from src.internationalize.generate_file import generate_file -from src.internationalize.helpers import get_json +import os +from src.internationalize.helpers import generate_file # run tests using python -m tests.test_generate_file at i18nilize directory level -class TestGenerateFile(unittest.TestCase): - generate_file() - data = get_json("src/internationalize/jsonFile/translations.json") +class TestGenerateFile(unittest.TestCase): + def setUp(self): + self.TEST_TOKEN = '85124f79-0829-4b80-8b5c-d52700d86e46' - def test_token(self): - self.assertEqual(self.data['Token'], "85124f79-0829-4b80-8b5c-d52700d86e46") - - def test_translations(self): - translations = self.data['translations'] - self.assertEqual(len(translations), 2) + @patch('src.internationalize.helpers.requests.get') + def test_generate_file_success(self, mock_get): + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + 'hello': 'hola', + 'thanks': 'gracias' + } + mock_get.return_value = mock_response + + generate_file('spanish', self.TEST_TOKEN) + + expected_file_path = './src/internationalize/languages/spanish.json' + self.assertTrue(os.path.exists(expected_file_path)) - # French - self.assertEqual(translations[0]['language'], "French") - self.assertEqual(translations[0]['hello'], "bonjour") - self.assertEqual(translations[0]['No'], "Non") - self.assertEqual(translations[0]['Why'], "pourquoi") + with open (expected_file_path, 'r') as file: + content = file.read() + expected_content = json.dumps(mock_response.json.return_value, indent = 4) + self.assertEqual(content, expected_content) - # Spanish - self.assertEqual(translations[1]['language'], "Spanish") - self.assertEqual(translations[1]['hello'], "Hola") + @patch('src.internationalize.helpers.requests.get') + def test_generate_file_error(self, mock_get): + mock_response = Mock() + mock_response.status_code = 404 + mock_get.return_value = mock_response + + generate_file('french', self.TEST_TOKEN) + + expected_file_path = './src/internationalize/languages/french.json' + self.assertFalse(os.path.exists(expected_file_path)) -unittest.main() \ No newline at end of file +if __name__ == '__main__': + unittest.main()