Skip to content

Commit d5a4a1a

Browse files
author
Dimitrios Bendilas
authored
Merge pull request #32 from transifex/migrate-text-mode
Add direct text migration mode
2 parents 053e036 + f008c95 commit d5a4a1a

3 files changed

Lines changed: 110 additions & 14 deletions

File tree

tests/native/django/test_commands/test_migratetransifex.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.core.management import call_command
66
from tests.native.django.test_tools.test_migrations.test_templatetags import (
77
DJANGO_TEMPLATE, TRANSIFEX_TEMPLATE)
8+
from transifex.common.console import Color
89
from transifex.native.django.management.commands.transifex import Command
910
from transifex.native.django.management.common import TranslatableFile
1011
from transifex.native.tools.migrations.review import (FileReviewPolicy,
@@ -341,3 +342,45 @@ def test_replace_save_string_review(mock_find_files, mock_read,
341342
assert mock_save_file.call_args[0][0] == 'dir1/dir2/1.html'
342343
migration_compile = mock_save_file.call_args[0][1]
343344
assert migration_compile() == HTML_COMPILED_1
345+
346+
347+
@mock.patch('transifex.common.console.Color.echo')
348+
def test_text_migration_template_code(mock_echo):
349+
"""Test the mode that migrates directly given text instead of files
350+
(Django HTML templates)."""
351+
command = Command()
352+
call_command(command, 'migrate', text=DJANGO_TEMPLATE)
353+
expected = Color.format(
354+
'\n[high]Transifex Native syntax:[end]\n[green]{}[end]'.format(
355+
TRANSIFEX_TEMPLATE
356+
)
357+
)
358+
actual = Color.format(mock_echo.call_args_list[1][0][0])
359+
assert expected == actual
360+
361+
# Make sure it's idempotent
362+
mock_echo.reset_mock()
363+
call_command(command, 'migrate', text=TRANSIFEX_TEMPLATE)
364+
actual = Color.format(mock_echo.call_args_list[1][0][0])
365+
assert expected == actual
366+
367+
368+
@mock.patch('transifex.common.console.Color.echo')
369+
def test_text_migration_python_code(mock_echo):
370+
"""Test the mode that migrates directly given text instead of files
371+
(Python/gettext code)."""
372+
command = Command()
373+
call_command(command, 'migrate', text=PYTHON_SAMPLE)
374+
expected = Color.format(
375+
'\n[high]Transifex Native syntax:[end]\n[green]{}[end]'.format(
376+
PYTHON_SAMPLE_MIGRATED
377+
)
378+
)
379+
native = Color.format(mock_echo.call_args_list[1][0][0])
380+
assert expected == native
381+
382+
# Make sure it's idempotent
383+
mock_echo.reset_mock()
384+
call_command(command, 'migrate', text=PYTHON_SAMPLE_MIGRATED)
385+
actual = Color.format(mock_echo.call_args_list[1][0][0])
386+
assert expected == actual

transifex/native/django/management/utils/migrate.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from transifex.native.tools.migrations.execution import (MARK_POLICY_OPTIONS,
1414
REVIEW_POLICY_OPTIONS,
1515
SAVE_POLICY_OPTIONS,
16-
MigrationExecutor)
16+
MigrationExecutor,
17+
migrate_text)
1718
from transifex.native.tools.migrations.gettext import (GettextMethods,
1819
GettextMigrationBuilder)
1920

@@ -93,6 +94,12 @@ def add_arguments(self, subparsers):
9394
'--path', '-p', dest='path',
9495
help='The path of the files to migrate. Finds files recursively.',
9596
)
97+
parser.add_argument(
98+
'--text', '-t', dest='text', default='',
99+
help='If set, the migration command will display the result '
100+
'of converting the given text to Transifex Native syntax, '
101+
'and then exit.',
102+
)
96103
parser.add_argument(
97104
'--save', dest='save_policy', default='new',
98105
help=('Determines where the migrated content will be saved: \n' +
@@ -120,6 +127,22 @@ def handle(self, *args, **options):
120127
self.stats = {
121128
'processed_files': 0, 'migrations': [], 'saved': [], 'errors': [],
122129
}
130+
131+
# Create a reusable migrator for templates code
132+
self.django_migration_builder = DjangoTagMigrationBuilder()
133+
self.gettext_migration_builder = GettextMigrationBuilder(
134+
methods=GettextMethods(**GETTEXT_FUNCTIONS),
135+
import_statement=T_IMPORT,
136+
)
137+
138+
# -- Text mode: simply transform the given text and exit
139+
text = options['text']
140+
if text:
141+
migrate_text(text, self._migrate_text)
142+
return
143+
144+
# -- File mode: read all files based on the given options and migrate
145+
# each of them
123146
self.executor = MigrationExecutor(
124147
options, file_migrator_func=self._migrate_file,
125148
)
@@ -138,18 +161,27 @@ def handle(self, *args, **options):
138161
else:
139162
files = self._find_files(self.path, 'migrate')
140163

141-
# Create a reusable migrator for templates code
142-
self.django_migration_builder = DjangoTagMigrationBuilder()
143-
self.gettext_migration_builder = GettextMigrationBuilder(
144-
methods=GettextMethods(**GETTEXT_FUNCTIONS),
145-
import_statement=T_IMPORT,
146-
)
147-
148164
# Execute the migration
149165
self.executor.migrate_files(files)
150166

167+
def _migrate_text(self, text):
168+
"""Create a migration to Native syntax for the given string.
169+
170+
Supports both Python files and Django template files.
171+
172+
:param unicode text: the code string
173+
:return: an object with the migration info
174+
:rtype: FileMigration
175+
"""
176+
# Template code
177+
if '{%' in text:
178+
return self.django_migration_builder.build_migration(text, '')
179+
# Python code
180+
else:
181+
return self.gettext_migration_builder.build_migration(text, '')
182+
151183
def _migrate_file(self, translatable_file):
152-
"""Extract source strings from the given file.
184+
"""Create a migration to Native syntax for the given file.
153185
154186
Supports both Python files and Django template files.
155187

transifex/native/tools/migrations/execution.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ class MigrationExecutor(object):
6060
"""Responsible for orchestrating a migration of multiple files
6161
to Transifex Native syntax.
6262
63-
6463
It guides the user throughout the process, providing important
65-
feedback in the console. It supports various "review" and "save"
64+
feedback in the console. It supports various "review", "save" and "mark"
6665
policies, that determine what the user is asked to accept or reject
6766
before being saved, and the file location the changes are saved in.
6867
@@ -81,9 +80,9 @@ def __init__(self, options, file_migrator_func):
8180
current location
8281
- 'review_policy' (see REVIEW_POLICY_OPTIONS)
8382
- 'save_policy' (SAVE_POLICY_OPTIONS)
84-
:param func file_migrator_func: a function that is responsible for
85-
getting a TranslatableFile object and returning a FileMigration
86-
object
83+
:param callable file_migrator_func: a callable that is responsible for
84+
getting an object (e.g. a TranslatableFile) and returning
85+
a FileMigration object
8786
"""
8887
self.options = options
8988
self.file_migrator_func = file_migrator_func
@@ -428,3 +427,25 @@ def _show_results(self, files, stats):
428427
Color.echo(errors_str)
429428

430429
Color.echo('')
430+
431+
432+
def migrate_text(text, migrator_func):
433+
"""Convert the given text from the original framework to Native syntax.
434+
435+
Supports both HTML/template syntax and Python/gettext syntax.
436+
Prints out the result in the console.
437+
438+
:param unicode text: the text to migrate to Native syntax
439+
:param callable migrator_func: a Callable[unicode] -> FileMigration object
440+
that converts syntax to Transifex Native; provided externally
441+
so that it can support any Python framework (e.g. Django)
442+
"""
443+
Color.echo(
444+
'[high]Original syntax:[end]\n[red]{}[end]'.format(text)
445+
)
446+
file_migration = migrator_func(text)
447+
Color.echo(
448+
'\n[high]Transifex Native syntax:[end]\n[green]{}[end]'.format(
449+
file_migration.compile()
450+
)
451+
)

0 commit comments

Comments
 (0)