diff --git a/CHANGELOG.md b/CHANGELOG.md index 84695a0d..2152eaf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## Unreleased + + - Remove `fluent.migrate`. + + The migration code has been moved into its own repository: + [fluent-migration](https://hg.mozilla.org/l10n/fluent-migration). See + [bug 1445881](https://bugzilla.mozilla.org/show_bug.cgi?id=1445881) for + more information about the move. + ## fluent 0.6.4 (March 1, 2018) - use compare-locales for plurals ordering ([bug 1415844](https://bugzilla.mozilla.org/show_bug.cgi?id=1415844)) diff --git a/fluent/migrate/__init__.py b/fluent/migrate/__init__.py deleted file mode 100644 index 93c8ab9a..00000000 --- a/fluent/migrate/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# coding=utf8 - -from .transforms import ( # noqa: F401 - CONCAT, COPY, PLURALS, REPLACE, REPLACE_IN_TEXT -) diff --git a/fluent/migrate/changesets.py b/fluent/migrate/changesets.py deleted file mode 100644 index d0fd396f..00000000 --- a/fluent/migrate/changesets.py +++ /dev/null @@ -1,58 +0,0 @@ -# coding=utf8 - -import time - - -def by_first_commit(item): - """Order two changesets by their first commit date.""" - return item['first_commit'] - - -def convert_blame_to_changesets(blame_json): - """Convert a blame dict into a list of changesets. - - The blame information in `blame_json` should be a dict of the following - structure: - - { - 'authors': [ - 'A.N. Author ', - ], - 'blame': { - 'path/one': { - 'key1': [0, 1346095921.0], - }, - } - } - - It will be transformed into a list of changesets which can be fed into - `MergeContext.serialize_changeset`: - - [ - { - 'author': 'A.N. Author ', - 'first_commit': 1346095921.0, - 'changes': { - ('path/one', 'key1'), - } - }, - ] - - """ - now = time.time() - changesets = [ - { - 'author': author, - 'first_commit': now, - 'changes': set() - } for author in blame_json['authors'] - ] - - for path, keys_info in blame_json['blame'].items(): - for key, (author_index, timestamp) in keys_info.items(): - changeset = changesets[author_index] - changeset['changes'].add((path, key)) - if timestamp < changeset['first_commit']: - changeset['first_commit'] = timestamp - - return sorted(changesets, key=by_first_commit) diff --git a/fluent/migrate/context.py b/fluent/migrate/context.py deleted file mode 100644 index 309fd2ef..00000000 --- a/fluent/migrate/context.py +++ /dev/null @@ -1,398 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import os -import codecs -from functools import partial -import logging - -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest - -import fluent.syntax.ast as FTL -from fluent.syntax.parser import FluentParser -from fluent.syntax.serializer import FluentSerializer -from fluent.util import fold -from compare_locales.parser import getParser -from compare_locales.plurals import CATEGORIES_BY_LOCALE - -from .transforms import Source -from .merge import merge_resource -from .util import get_message -from .errors import ( - EmptyLocalizationError, NotSupportedError, UnreadableReferenceError) - - -class MergeContext(object): - """Stateful context for merging translation resources. - - `MergeContext` must be configured with the target language and the - directory locations of the input data. - - The transformation takes four types of input data: - - - The en-US FTL reference files which will be used as templates for - message order, comments and sections. - - - The current FTL files for the given language. - - - The legacy (DTD, properties) translation files for the given - language. The translations from these files will be transformed - into FTL and merged into the existing FTL files for this language. - - - A list of `FTL.Message` objects some of whose nodes are special - helper or transform nodes: - - helpers: EXTERNAL_ARGUMENT, MESSAGE_REFERENCE - transforms: COPY, REPLACE_IN_TEXT, REPLACE, PLURALS, CONCAT - """ - - def __init__(self, lang, reference_dir, localization_dir): - self.fluent_parser = FluentParser(with_spans=False) - self.fluent_serializer = FluentSerializer() - - # An iterable of plural category names relevant to the context's - # language. E.g. ('one', 'other') for English. - try: - self.plural_categories = CATEGORIES_BY_LOCALE[lang] - except IndexError as e: - logging.getLogger('migrate').warn(e) - self.plural_categories = ('one', 'other') - - # Paths to directories with input data, relative to CWD. - self.reference_dir = reference_dir - self.localization_dir = localization_dir - - # Parsed input resources stored by resource path. - self.reference_resources = {} - self.localization_resources = {} - - # An iterable of `FTL.Message` objects some of whose nodes can be the - # transform operations. - self.transforms = {} - - # A dict whose keys are `(path, key)` tuples corresponding to target - # FTL translations, and values are sets of `(path, key)` tuples - # corresponding to localized entities which will be migrated. - self.dependencies = {} - - def read_ftl_resource(self, path): - """Read an FTL resource and parse it into an AST.""" - f = codecs.open(path, 'r', 'utf8') - try: - contents = f.read() - except UnicodeDecodeError as err: - logger = logging.getLogger('migrate') - logger.warn('Unable to read file {}: {}'.format(path, err)) - raise err - finally: - f.close() - - ast = self.fluent_parser.parse(contents) - - annots = [ - annot - for entry in ast.body - for annot in entry.annotations - ] - - if len(annots): - logger = logging.getLogger('migrate') - for annot in annots: - msg = annot.message - logger.warn('Syntax error in {}: {}'.format(path, msg)) - - return ast - - def read_legacy_resource(self, path): - """Read a legacy resource and parse it into a dict.""" - parser = getParser(path) - parser.readFile(path) - # Transform the parsed result which is an iterator into a dict. - return {entity.key: entity.val for entity in parser} - - def read_reference_ftl(self, path): - """Read and parse a reference FTL file. - - A missing resource file is a fatal error and will raise an - UnreadableReferenceError. - """ - fullpath = os.path.join(self.reference_dir, path) - try: - return self.read_ftl_resource(fullpath) - except IOError as err: - error_message = 'Missing reference file: {}'.format(fullpath) - logging.getLogger('migrate').error(error_message) - raise UnreadableReferenceError(error_message) - except UnicodeDecodeError as err: - error_message = 'Error reading file {}: {}'.format(fullpath, err) - logging.getLogger('migrate').error(error_message) - raise UnreadableReferenceError(error_message) - - def read_localization_ftl(self, path): - """Read and parse an existing localization FTL file. - - Create a new FTL.Resource if the file doesn't exist or can't be - decoded. - """ - fullpath = os.path.join(self.localization_dir, path) - try: - return self.read_ftl_resource(fullpath) - except IOError: - logger = logging.getLogger('migrate') - logger.info( - 'Localization file {} does not exist and ' - 'it will be created'.format(path)) - return FTL.Resource() - except UnicodeDecodeError: - logger = logging.getLogger('migrate') - logger.warn( - 'Localization file {} has broken encoding. ' - 'It will be re-created and some translations ' - 'may be lost'.format(path)) - return FTL.Resource() - - def maybe_add_localization(self, path): - """Add a localization resource to migrate translations from. - - Only legacy resources can be added as migration sources. The resource - may be missing on disk. - - Uses a compare-locales parser to create a dict of (key, string value) - tuples. - """ - if path.endswith('.ftl'): - error_message = ( - 'Migrating translations from Fluent files is not supported ' - '({})'.format(path)) - logging.getLogger('migrate').error(error_message) - raise NotSupportedError(error_message) - - try: - fullpath = os.path.join(self.localization_dir, path) - collection = self.read_legacy_resource(fullpath) - except IOError: - logger = logging.getLogger('migrate') - logger.warn('Missing localization file: {}'.format(path)) - else: - self.localization_resources[path] = collection - - def add_transforms(self, target, reference, transforms): - """Define transforms for target using reference as template. - - `target` is a path of the destination FTL file relative to the - localization directory. `reference` is a path to the template FTL - file relative to the reference directory. - - Each transform is an extended FTL node with `Transform` nodes as some - values. Transforms are stored in their lazy AST form until - `merge_changeset` is called, at which point they are evaluated to real - FTL nodes with migrated translations. - - Each transform is scanned for `Source` nodes which will be used to - build the list of dependencies for the transformed message. - """ - def get_sources(acc, cur): - if isinstance(cur, Source): - acc.add((cur.path, cur.key)) - return acc - - reference_ast = self.read_reference_ftl(reference) - self.reference_resources[target] = reference_ast - - for node in transforms: - ident = node.id.name - # Scan `node` for `Source` nodes and collect the information they - # store into a set of dependencies. - dependencies = fold(get_sources, node, set()) - # Set these sources as dependencies for the current transform. - self.dependencies[(target, ident)] = dependencies - - # The target Fluent message should exist in the reference file. If - # it doesn't, it's probably a typo. - if get_message(reference_ast.body, ident) is None: - logger = logging.getLogger('migrate') - logger.warn( - '{} "{}" was not found in {}'.format( - type(node).__name__, ident, reference)) - - # Keep track of localization resource paths which were defined as - # sources in the transforms. - expected_paths = set() - - # Read all legacy translation files defined in Source transforms. This - # may fail but a single missing legacy resource doesn't mean that the - # migration can't succeed. - for dependencies in self.dependencies.values(): - for path in set(path for path, _ in dependencies): - expected_paths.add(path) - self.maybe_add_localization(path) - - # However, if all legacy resources are missing, bail out early. There - # are no translations to migrate. We'd also get errors in hg annotate. - if len(expected_paths) > 0 and len(self.localization_resources) == 0: - error_message = 'No localization files were found' - logging.getLogger('migrate').error(error_message) - raise EmptyLocalizationError(error_message) - - # Add the current transforms to any other transforms added earlier for - # this path. - path_transforms = self.transforms.setdefault(target, []) - path_transforms += transforms - - if target not in self.localization_resources: - target_ast = self.read_localization_ftl(target) - self.localization_resources[target] = target_ast - - def get_source(self, path, key): - """Get an entity value from a localized legacy source. - - Used by the `Source` transform. - """ - resource = self.localization_resources[path] - return resource.get(key, None) - - def messages_equal(self, res1, res2): - """Compare messages and terms of two FTL resources. - - Uses FTL.BaseNode.equals to compare all messages/terms - in two FTL resources. - If the order or number of messages differ, the result is also False. - """ - def message_id(message): - "Return the message's identifer name for sorting purposes." - return message.id.name - - messages1 = sorted( - (entry for entry in res1.body - if isinstance(entry, FTL.Message) - or isinstance(entry, FTL.Term)), - key=message_id) - messages2 = sorted( - (entry for entry in res2.body - if isinstance(entry, FTL.Message) - or isinstance(entry, FTL.Term)), - key=message_id) - for msg1, msg2 in zip_longest(messages1, messages2): - if msg1 is None or msg2 is None: - return False - if not msg1.equals(msg2): - return False - return True - - def merge_changeset(self, changeset=None, known_translations=None): - """Return a generator of FTL ASTs for the changeset. - - The input data must be configured earlier using the `add_*` methods. - if given, `changeset` must be a set of (path, key) tuples describing - which legacy translations are to be merged. If `changeset` is None, - all legacy translations will be allowed to be migrated in a single - changeset. - - We use the `in_changeset` method to determine if a message should be - migrated for the given changeset. - - Given `changeset`, return a dict whose keys are resource paths and - values are `FTL.Resource` instances. The values will also be used to - update this context's existing localization resources. - """ - - if changeset is None: - # Merge all known legacy translations. Used in tests. - changeset = { - (path, key) - for path, strings in self.localization_resources.iteritems() - if not path.endswith('.ftl') - for key in strings.iterkeys() - } - - if known_translations is None: - known_translations = changeset - - for path, reference in self.reference_resources.iteritems(): - current = self.localization_resources[path] - transforms = self.transforms.get(path, []) - in_changeset = partial( - self.in_changeset, changeset, known_translations, path - ) - - # Merge legacy translations with the existing ones using the - # reference as a template. - snapshot = merge_resource( - self, reference, current, transforms, in_changeset - ) - - # Skip this path if the messages in the merged snapshot are - # identical to those in the current state of the localization file. - # This may happen when: - # - # - none of the transforms is in the changset, or - # - all messages which would be migrated by the context's - # transforms already exist in the current state. - if self.messages_equal(current, snapshot): - continue - - # Store the merged snapshot on the context so that the next merge - # already takes it into account as the existing localization. - self.localization_resources[path] = snapshot - - # The result for this path is a complete `FTL.Resource`. - yield path, snapshot - - def in_changeset(self, changeset, known_translations, path, ident): - """Check if a message should be migrated in this changeset. - - The message is identified by path and ident. - - - A message will be migrated only if all of its dependencies - are present in the currently processed changeset. - - If a transform defined for this message points to a missing - legacy translation, this message will not be merged. The - missing legacy dependency won't be present in the changeset. - - This also means that partially translated messages (e.g. - constructed from two legacy strings out of which only one is - avaiable) will never be migrated. - """ - message_deps = self.dependencies.get((path, ident), None) - - # Don't merge if we don't have a transform for this message. - if message_deps is None: - return False - - # As a special case, if a transform exists but has no - # dependecies, it's a hardcoded `FTL.Node` which doesn't - # migrate any existing translation but rather creates a new - # one. Merge it. - if len(message_deps) == 0: - return True - - # Make sure all the dependencies are present in the current - # changeset. Partial migrations are not currently supported. - # See https://bugzilla.mozilla.org/show_bug.cgi?id=1321271 - # We only return True if our current changeset touches - # the transform, and we have all of the dependencies. - active_deps = message_deps & changeset - available_deps = message_deps & known_translations - return active_deps and message_deps == available_deps - - def serialize_changeset(self, changeset, known_translations=None): - """Return a dict of serialized FTLs for the changeset. - - Given `changeset`, return a dict whose keys are resource paths and - values are serialized FTL snapshots. - """ - - return { - path: self.fluent_serializer.serialize(snapshot) - for path, snapshot in self.merge_changeset( - changeset, known_translations - ) - } - - -logging.basicConfig() diff --git a/fluent/migrate/errors.py b/fluent/migrate/errors.py deleted file mode 100644 index 466ecf70..00000000 --- a/fluent/migrate/errors.py +++ /dev/null @@ -1,14 +0,0 @@ -class MigrationError(ValueError): - pass - - -class EmptyLocalizationError(MigrationError): - pass - - -class NotSupportedError(MigrationError): - pass - - -class UnreadableReferenceError(MigrationError): - pass diff --git a/fluent/migrate/helpers.py b/fluent/migrate/helpers.py deleted file mode 100644 index f0e9c088..00000000 --- a/fluent/migrate/helpers.py +++ /dev/null @@ -1,29 +0,0 @@ -# coding=utf8 -"""Fluent AST helpers. - -The functions defined in this module offer a shorthand for defining common AST -nodes. - -They take a string argument and immediately return a corresponding AST node. -(As opposed to Transforms which are AST nodes on their own and only return the -migrated AST nodes when they are evaluated by a MergeContext.) """ - -from __future__ import unicode_literals - -import fluent.syntax.ast as FTL - - -def EXTERNAL_ARGUMENT(name): - """Create an ExternalArgument expression.""" - - return FTL.ExternalArgument( - id=FTL.Identifier(name) - ) - - -def MESSAGE_REFERENCE(name): - """Create a MessageReference expression.""" - - return FTL.MessageReference( - id=FTL.Identifier(name) - ) diff --git a/fluent/migrate/merge.py b/fluent/migrate/merge.py deleted file mode 100644 index 86829652..00000000 --- a/fluent/migrate/merge.py +++ /dev/null @@ -1,55 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import fluent.syntax.ast as FTL - -from .transforms import evaluate -from .util import get_message, get_transform - - -def merge_resource(ctx, reference, current, transforms, in_changeset): - """Transform legacy translations into FTL. - - Use the `reference` FTL AST as a template. For each en-US string in the - reference, first check for an existing translation in the current FTL - `localization` and use it if it's present; then if the string has - a transform defined in the migration specification and if it's in the - currently processed changeset, evaluate the transform. - """ - - def merge_body(body): - return [ - entry - for entry in map(merge_entry, body) - if entry is not None - ] - - def merge_entry(entry): - # All standalone comments will be merged. - if isinstance(entry, FTL.BaseComment): - return entry - - # Ignore Junk - if isinstance(entry, FTL.Junk): - return None - - ident = entry.id.name - - # If the message is present in the existing localization, we add it to - # the resulting resource. This ensures consecutive merges don't remove - # translations but rather create supersets of them. - existing = get_message(current.body, ident) - if existing is not None: - return existing - - transform = get_transform(transforms, ident) - - # Make sure this message is supposed to be migrated as part of the - # current changeset. - if transform is not None and in_changeset(ident): - if transform.comment is None: - transform.comment = entry.comment - return evaluate(ctx, transform) - - body = merge_body(reference.body) - return FTL.Resource(body) diff --git a/fluent/migrate/transforms.py b/fluent/migrate/transforms.py deleted file mode 100644 index 616707e9..00000000 --- a/fluent/migrate/transforms.py +++ /dev/null @@ -1,379 +0,0 @@ -# coding=utf8 -"""Migration Transforms. - -Transforms are AST nodes which describe how legacy translations should be -migrated. They are created inert and only return the migrated AST nodes when -they are evaluated by a MergeContext. - -All Transforms evaluate to Fluent Patterns. This makes them suitable for -defining migrations of values of message, attributes and variants. The special -CONCAT Transform is capable of joining multiple Patterns returned by evaluating -other Transforms into a single Pattern. It can also concatenate Pattern -elements: TextElements and Placeables. - -The COPY, REPLACE and PLURALS Transforms inherit from Source which is a special -AST Node defining the location (the file path and the id) of the legacy -translation. During the migration, the current MergeContext scans the -migration spec for Source nodes and extracts the information about all legacy -translations being migrated. For instance, - - COPY('file.dtd', 'hello') - -is equivalent to: - - FTL.Pattern([ - Source('file.dtd', 'hello') - ]) - -Sometimes it's useful to work with text rather than (path, key) source -definitions. This is the case when the migrated translation requires some -hardcoded text, e.g. and when multiple translations become a single -one with a DOM overlay. In such cases it's best to use FTL.TextElements: - - FTL.Message( - id=FTL.Identifier('update-failed'), - value=CONCAT( - COPY('aboutDialog.dtd', 'update.failed.start'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'update.failed.linkText'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'update.failed.end'), - ) - ) - -The REPLACE_IN_TEXT Transform also takes TextElements as input, making it -possible to pass it as the foreach function of the PLURALS Transform. In the -example below, each slice of the plural string is converted into a -TextElement by PLURALS and then run through the REPLACE_IN_TEXT transform. - - FTL.Message( - FTL.Identifier('delete-all'), - value=PLURALS( - 'aboutDownloads.dtd', - 'deleteAll', - EXTERNAL_ARGUMENT('num'), - lambda text: REPLACE_IN_TEXT( - text, - { - '#1': EXTERNAL_ARGUMENT('num') - } - ) - ) - ) -""" - -from __future__ import unicode_literals -import re - -import fluent.syntax.ast as FTL -from .errors import NotSupportedError - - -def evaluate(ctx, node): - def eval_node(subnode): - if isinstance(subnode, Transform): - return subnode(ctx) - else: - return subnode - - return node.traverse(eval_node) - - -def get_text(element): - '''Get text content of a PatternElement.''' - if isinstance(element, FTL.TextElement): - return element.value - if isinstance(element, FTL.Placeable): - if isinstance(element.expression, FTL.StringExpression): - return element.expression.value - else: - return None - raise RuntimeError('Expected PatternElement') - - -def chain_elements(elements): - '''Flatten a list of FTL nodes into an iterator over PatternElements.''' - for element in elements: - if isinstance(element, FTL.Pattern): - # PY3 yield from element.elements - for child in element.elements: - yield child - elif isinstance(element, FTL.PatternElement): - yield element - elif isinstance(element, FTL.Expression): - yield FTL.Placeable(element) - else: - raise RuntimeError( - 'Expected Pattern, PatternElement or Expression') - - -re_leading_ws = re.compile(r'^(?P\s+)(?P.*?)$') -re_trailing_ws = re.compile(r'^(?P.*?)(?P\s+)$') - - -def extract_whitespace(regex, element): - '''Extract leading or trailing whitespace from a TextElement. - - Return a tuple of (Placeable, TextElement) in which the Placeable - encodes the extracted whitespace as a StringExpression and the - TextElement has the same amount of whitespace removed. The - Placeable with the extracted whitespace is always returned first. - ''' - match = re.search(regex, element.value) - if match: - whitespace = match.group('whitespace') - placeable = FTL.Placeable(FTL.StringExpression(whitespace)) - if whitespace == element.value: - return placeable, None - else: - return placeable, FTL.TextElement(match.group('text')) - else: - return None, element - - -class Transform(FTL.BaseNode): - def __call__(self, ctx): - raise NotImplementedError - - @staticmethod - def pattern_of(*elements): - normalized = [] - - # Normalize text content: convert all text to TextElements, join - # adjacent text and prune empty. - for current in chain_elements(elements): - current_text = get_text(current) - if current_text is None: - normalized.append(current) - continue - - previous = normalized[-1] if len(normalized) else None - if isinstance(previous, FTL.TextElement): - # Join adjacent TextElements - previous.value += current_text - elif len(current_text) > 0: - # Normalize non-empty text to a TextElement - normalized.append(FTL.TextElement(current_text)) - else: - # Prune empty text - pass - - # Handle empty values - if len(normalized) == 0: - empty = FTL.Placeable(FTL.StringExpression('')) - return FTL.Pattern([empty]) - - # Handle explicit leading whitespace - if isinstance(normalized[0], FTL.TextElement): - ws, text = extract_whitespace(re_leading_ws, normalized[0]) - normalized[:1] = [ws, text] - - # Handle explicit trailing whitespace - if isinstance(normalized[-1], FTL.TextElement): - ws, text = extract_whitespace(re_trailing_ws, normalized[-1]) - normalized[-1:] = [text, ws] - - return FTL.Pattern([ - element - for element in normalized - if element is not None - ]) - - -class Source(Transform): - """Declare the source translation to be migrated with other transforms. - - When evaluated, `Source` returns a TextElement with the content from the - source translation. Escaped characters are unescaped by the - compare-locales parser according to the file format: - - - in properties files: \\uXXXX, - - in DTD files: known named, decimal, and hexadecimal HTML entities. - - Consult the following files for the list of known named HTML entities: - - https://github.com/python/cpython/blob/2.7/Lib/htmlentitydefs.py - https://github.com/python/cpython/blob/3.6/Lib/html/entities.py - - """ - - def __init__(self, path, key): - if path.endswith('.ftl'): - raise NotSupportedError( - 'Migrating translations from Fluent files is not supported ' - '({})'.format(path)) - - self.path = path - self.key = key - - def __call__(self, ctx): - text = ctx.get_source(self.path, self.key) - return FTL.TextElement(text) - - -class COPY(Source): - """Create a Pattern with the translation value from the given source.""" - - def __call__(self, ctx): - element = super(COPY, self).__call__(ctx) - return Transform.pattern_of(element) - - -class REPLACE_IN_TEXT(Transform): - """Create a Pattern from a TextElement and replace legacy placeables. - - The original placeables are defined as keys on the `replacements` dict. - For each key the value is defined as a FTL Pattern, Placeable, - TextElement or Expressions to be interpolated. - """ - - def __init__(self, element, replacements): - self.element = element - self.replacements = replacements - - def __call__(self, ctx): - # Only replace placeables which are present in the translation. - replacements = { - key: evaluate(ctx, repl) - for key, repl in self.replacements.iteritems() - if key in self.element.value - } - - # Order the original placeables by their position in the translation. - keys_in_order = sorted( - replacements.keys(), - lambda x, y: - self.element.value.find(x) - self.element.value.find(y) - ) - - # A list of PatternElements built from the legacy translation and the - # FTL replacements. It may contain empty or adjacent TextElements. - elements = [] - tail = self.element.value - - # Convert original placeables and text into FTL Nodes. For each - # original placeable the translation will be partitioned around it and - # the text before it will be converted into an `FTL.TextElement` and - # the placeable will be replaced with its replacement. - for key in keys_in_order: - before, key, tail = tail.partition(key) - elements.append(FTL.TextElement(before)) - elements.append(replacements[key]) - - # Dont' forget about the tail after the loop ends. - elements.append(FTL.TextElement(tail)) - return Transform.pattern_of(*elements) - - -class REPLACE(Source): - """Create a Pattern with interpolations from given source. - - Interpolations in the translation value from the given source will be - replaced with FTL placeables using the `REPLACE_IN_TEXT` transform. - """ - - def __init__(self, path, key, replacements): - super(REPLACE, self).__init__(path, key) - self.replacements = replacements - - def __call__(self, ctx): - element = super(REPLACE, self).__call__(ctx) - return REPLACE_IN_TEXT(element, self.replacements)(ctx) - - -class PLURALS(Source): - """Create a Pattern with plurals from given source. - - Build an `FTL.SelectExpression` with the supplied `selector` and variants - extracted from the source. The original translation should be a - semicolon-separated list of plural forms. Each form will be converted - into a TextElement and run through the `foreach` function, which should - return an `FTL.Node` or a `Transform`. By default, the `foreach` function - creates a valid Pattern from the TextElement passed into it. - """ - DEFAULT_ORDER = ('zero', 'one', 'two', 'few', 'many', 'other') - - def __init__(self, path, key, selector, foreach=Transform.pattern_of): - super(PLURALS, self).__init__(path, key) - self.selector = selector - self.foreach = foreach - - def __call__(self, ctx): - element = super(PLURALS, self).__call__(ctx) - selector = evaluate(ctx, self.selector) - keys = ctx.plural_categories - forms = [ - FTL.TextElement(part) - for part in element.value.split(';') - ] - - # The default CLDR form should be the last we have in DEFAULT_ORDER, - # usually `other`, but in some cases `many`. If we don't have a variant - # for that, we'll append one, using the, in CLDR order, last existing - # variant in the legacy translation. That may or may not be the last - # variant. - default_key = [ - key for key in reversed(self.DEFAULT_ORDER) if key in keys - ][0] - - # Match keys to legacy forms in the order they are defined in Gecko's - # PluralForm.jsm. Filter out empty forms. - pairs = [ - (key, var) - for key, var in zip(keys, forms) - if var.value - ] - - # A special case for legacy translations which don't define any - # plural forms. - if len(pairs) == 0: - return Transform.pattern_of() - - # A special case for languages with one plural category or one legacy - # variant. We don't need to insert a SelectExpression for them. - if len(pairs) == 1: - _, only_form = pairs[0] - only_variant = evaluate(ctx, self.foreach(only_form)) - return Transform.pattern_of(only_variant) - - # Make sure the default key is defined. If it's missing, use the last - # form (in CLDR order) found in the legacy translation. - pairs.sort(key=lambda pair: self.DEFAULT_ORDER.index(pair[0])) - last_key, last_form = pairs[-1] - if last_key != default_key: - pairs.append((default_key, last_form)) - - def createVariant(key, form): - # Run the legacy plural form through `foreach` which returns an - # `FTL.Node` describing the transformation required for each - # variant. Then evaluate it to a migrated FTL node. - value = evaluate(ctx, self.foreach(form)) - return FTL.Variant( - key=FTL.VariantName(key), - value=value, - default=key == default_key - ) - - select = FTL.SelectExpression( - expression=selector, - variants=[ - createVariant(key, form) - for key, form in pairs - ] - ) - - return Transform.pattern_of(select) - - -class CONCAT(Transform): - """Create a new Pattern from Patterns, PatternElements and Expressions.""" - - def __init__(self, *elements, **kwargs): - # We want to support both passing elements as *elements in the - # migration specs and as elements=[]. The latter is used by - # FTL.BaseNode.traverse when it recreates the traversed node using its - # attributes as kwargs. - self.elements = list(kwargs.get('elements', elements)) - - def __call__(self, ctx): - return Transform.pattern_of(*self.elements) diff --git a/fluent/migrate/util.py b/fluent/migrate/util.py deleted file mode 100644 index 497aaab4..00000000 --- a/fluent/migrate/util.py +++ /dev/null @@ -1,59 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import fluent.syntax.ast as FTL -from fluent.syntax.parser import FluentParser -from fluent.util import ftl - - -fluent_parser = FluentParser(with_spans=False) - - -def parse(Parser, string): - if Parser is FluentParser: - return fluent_parser.parse(string) - - # Parsing a legacy resource. - - # Parse the string into the internal Context. - parser = Parser() - # compare-locales expects ASCII strings. - parser.readContents(string.encode('utf8')) - # Transform the parsed result which is an iterator into a dict. - return {ent.key: ent for ent in parser} - - -def ftl_resource_to_ast(code): - return fluent_parser.parse(ftl(code)) - - -def ftl_resource_to_json(code): - return fluent_parser.parse(ftl(code)).to_json() - - -def ftl_message_to_json(code): - return fluent_parser.parse_entry(ftl(code)).to_json() - - -def to_json(merged_iter): - return { - path: resource.to_json() - for path, resource in merged_iter - } - - -LOCALIZABLE_ENTRIES = (FTL.Message, FTL.Term) - - -def get_message(body, ident): - """Get message called `ident` from the `body` iterable.""" - for entity in body: - if isinstance(entity, LOCALIZABLE_ENTRIES) and entity.id.name == ident: - return entity - - -def get_transform(body, ident): - """Get entity called `ident` from the `body` iterable.""" - for transform in body: - if transform.id.name == ident: - return transform diff --git a/fluent/util.py b/fluent/util.py deleted file mode 100644 index 50a2ac9e..00000000 --- a/fluent/util.py +++ /dev/null @@ -1,44 +0,0 @@ -# coding=utf8 -import textwrap - -import fluent.syntax.ast as FTL - - -def ftl(code): - """Nicer indentation for FTL code. - - The code returned by this function is meant to be compared against the - output of the FTL Serializer. The input code will end with a newline to - match the output of the serializer. - """ - - # The code might be triple-quoted. - code = code.lstrip('\n') - - return textwrap.dedent(code) - - -def fold(fun, node, init): - """Reduce `node` to a single value using `fun`. - - Apply `fun` against an accumulator and each subnode of `node` (in postorder - traversal) to reduce it to a single value. - """ - - def fold_(vals, acc): - if not vals: - return acc - - head = list(vals)[0] - tail = list(vals)[1:] - - if isinstance(head, FTL.BaseNode): - acc = fold(fun, head, acc) - if isinstance(head, list): - acc = fold_(head, acc) - if isinstance(head, dict): - acc = fold_(head.values(), acc) - - return fold_(tail, fun(acc, head)) - - return fold_(vars(node).values(), init) diff --git a/setup.py b/setup.py index 4caae6d9..6d99cacd 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', ], - packages=['fluent', 'fluent.syntax', 'fluent.migrate'], + packages=['fluent', 'fluent.syntax'], tests_require=['six'], test_suite='tests.syntax' ) diff --git a/tests/migrate/__init__.py b/tests/migrate/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/migrate/fixtures/en-US/aboutDialog.ftl b/tests/migrate/fixtures/en-US/aboutDialog.ftl deleted file mode 100644 index 0fd4d946..00000000 --- a/tests/migrate/fixtures/en-US/aboutDialog.ftl +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -update-failed = Update failed. Download manually! -channel-desc = You are on the { $channelname } channel. -community = - { brand-short-name } is designed by - { vendor-short-name }, a global community - working together to… diff --git a/tests/migrate/fixtures/en-US/aboutDownloads.ftl b/tests/migrate/fixtures/en-US/aboutDownloads.ftl deleted file mode 100644 index c759e082..00000000 --- a/tests/migrate/fixtures/en-US/aboutDownloads.ftl +++ /dev/null @@ -1,39 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -title = Downloads -header = Your Downloads -empty = No Downloads -about = About Downloads - -open-menuitem = - .label = Open -retry-menuitem = - .label = Retry -remove-menuitem = - .label = Delete -pause-menuitem = - .label = Pause -resume-menuitem = - .label = Resume -cancel-menuitem = - .label = Cancel -remove-all-menuitem = - .label = Delete All - -delete-all-title = Delete All -delete-all-message = - { $num -> - [1] Delete this download? - *[other] Delete { $num } downloads? - } - -download-state-downloading = Downloading… -download-state-canceled = Canceled -download-state-failed = Failed -download-state-paused = Paused -download-state-starting = Starting… -download-state-unknown = Unknown - -download-size-unknown = Unknown size diff --git a/tests/migrate/fixtures/en-US/existing.ftl b/tests/migrate/fixtures/en-US/existing.ftl deleted file mode 100644 index 80d2f23b..00000000 --- a/tests/migrate/fixtures/en-US/existing.ftl +++ /dev/null @@ -1,2 +0,0 @@ -foo = foo -bar = Bar diff --git a/tests/migrate/fixtures/en-US/privacy.ftl b/tests/migrate/fixtures/en-US/privacy.ftl deleted file mode 100644 index c81f4e1b..00000000 --- a/tests/migrate/fixtures/en-US/privacy.ftl +++ /dev/null @@ -1,9 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -dnt-description = - Send websites a “Do Not Track” signal - that you don’t want to be tracked -dnt-learn-more = Learn more -dnt-always = Always diff --git a/tests/migrate/fixtures/en-US/toolbar.ftl b/tests/migrate/fixtures/en-US/toolbar.ftl deleted file mode 100644 index c102d7a9..00000000 --- a/tests/migrate/fixtures/en-US/toolbar.ftl +++ /dev/null @@ -1,24 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -urlbar-textbox = - .placeholder = Search or enter address - .accesskey = d - - -## Toolbar items - -view-bookmarks-broadcaster = - .label = Bookmarks -view-bookmarks-command = - .key = b -view-bookmarks-command-win = - .key = i - -view-history-broadcaster = - .label = History -view-history-command = - .key = h -view-tabs-broadcaster = - .label = Synced Tabs diff --git a/tests/migrate/fixtures/pl/aboutDialog.dtd b/tests/migrate/fixtures/pl/aboutDialog.dtd deleted file mode 100644 index 37629a32..00000000 --- a/tests/migrate/fixtures/pl/aboutDialog.dtd +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/tests/migrate/fixtures/pl/aboutDownloads.dtd b/tests/migrate/fixtures/pl/aboutDownloads.dtd deleted file mode 100644 index 2bc4fe77..00000000 --- a/tests/migrate/fixtures/pl/aboutDownloads.dtd +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - diff --git a/tests/migrate/fixtures/pl/aboutDownloads.properties b/tests/migrate/fixtures/pl/aboutDownloads.properties deleted file mode 100644 index 8a4c5cec..00000000 --- a/tests/migrate/fixtures/pl/aboutDownloads.properties +++ /dev/null @@ -1,12 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -downloadMessage.deleteAll=Usunąć pobrany plik?;Usunąć #1 pobrane pliki?;Usunąć #1 pobranych plików? -downloadState.downloading=Pobieranie… -downloadState.canceled=Anulowane -downloadState.failed=Nieudane -downloadState.paused=Wstrzymane -downloadState.starting=Rozpoczynanie… -downloadState.unknownSize=Nieznany rozmiar -downloadAction.deleteAll=Usuń wszystko diff --git a/tests/migrate/fixtures/pl/existing.dtd b/tests/migrate/fixtures/pl/existing.dtd deleted file mode 100644 index 5a403202..00000000 --- a/tests/migrate/fixtures/pl/existing.dtd +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/tests/migrate/fixtures/pl/existing.ftl b/tests/migrate/fixtures/pl/existing.ftl deleted file mode 100644 index 1251ea7c..00000000 --- a/tests/migrate/fixtures/pl/existing.ftl +++ /dev/null @@ -1,2 +0,0 @@ -bar = BAR -foo = FOO diff --git a/tests/migrate/fixtures/pl/privacy.dtd b/tests/migrate/fixtures/pl/privacy.dtd deleted file mode 100644 index 36878d2f..00000000 --- a/tests/migrate/fixtures/pl/privacy.dtd +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/tests/migrate/fixtures/pl/privacy.ftl b/tests/migrate/fixtures/pl/privacy.ftl deleted file mode 100644 index e41ad8dd..00000000 --- a/tests/migrate/fixtures/pl/privacy.ftl +++ /dev/null @@ -1,5 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -dnt-description = New Description in Polish diff --git a/tests/migrate/test_changesets.py b/tests/migrate/test_changesets.py deleted file mode 100644 index 52f423fd..00000000 --- a/tests/migrate/test_changesets.py +++ /dev/null @@ -1,50 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest - -from fluent.migrate.changesets import convert_blame_to_changesets - - -class TestBlameToChangesets(unittest.TestCase): - def test_convert(self): - blame = { - 'authors': [ - 'A', - 'B' - ], - 'blame': { - 'path/one': { - 'key1': [0, 1346095921.0], - 'key2': [1, 1218121409.0] - }, - 'path/two': { - 'key1': [1, 1440596526.0], - 'key3': [0, 1346095921.0] - } - } - } - - expected = [ - { - 'author': 'B', - 'first_commit': 1218121409.0, - 'changes': { - ('path/one', 'key2'), - ('path/two', 'key1'), - } - }, - { - 'author': 'A', - 'first_commit': 1346095921.0, - 'changes': { - ('path/one', 'key1'), - ('path/two', 'key3'), - } - }, - ] - - self.assertEqual( - convert_blame_to_changesets(blame), - expected - ) diff --git a/tests/migrate/test_concat.py b/tests/migrate/test_concat.py deleted file mode 100644 index 6d0ab3d1..00000000 --- a/tests/migrate/test_concat.py +++ /dev/null @@ -1,271 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser, DTDParser - -import fluent.syntax.ast as FTL -from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.helpers import EXTERNAL_ARGUMENT, MESSAGE_REFERENCE -from fluent.migrate.transforms import evaluate, CONCAT, COPY, REPLACE - - -class MockContext(unittest.TestCase): - maxDiff = None - - def get_source(self, path, key): - # Ignore path (test.properties) and get translations from self.strings - # defined in setUp. - return self.strings.get(key, None).val - - -class TestConcatCopy(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - hello = Hello, world! - hello.start = Hello,\\u0020 - hello.end = world! - empty = - empty.start = - empty.end = - whitespace.begin.start = \\u0020Hello,\\u0020 - whitespace.begin.end = world! - whitespace.end.start = Hello,\\u0020 - whitespace.end.end = world!\\u0020 - ''') - - def test_concat_one(self): - msg = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('test.properties', 'hello'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, world! - ''') - ) - - def test_concat_two(self): - msg = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('test.properties', 'hello.start'), - COPY('test.properties', 'hello.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, world! - ''') - ) - - def test_concat_empty_one(self): - msg = FTL.Message( - FTL.Identifier('empty'), - value=CONCAT( - COPY('test.properties', 'empty'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - empty = {""} - ''') - ) - - def test_concat_empty_two(self): - msg = FTL.Message( - FTL.Identifier('empty'), - value=CONCAT( - COPY('test.properties', 'empty.start'), - COPY('test.properties', 'empty.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - empty = {""} - ''') - ) - - def test_concat_nonempty_empty(self): - msg = FTL.Message( - FTL.Identifier('combined'), - value=CONCAT( - COPY('test.properties', 'hello'), - COPY('test.properties', 'empty'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - combined = Hello, world! - ''') - ) - - def test_concat_whitespace_begin(self): - msg = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('test.properties', 'whitespace.begin.start'), - COPY('test.properties', 'whitespace.begin.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = {" "}Hello, world! - ''') - ) - - def test_concat_whitespace_end(self): - msg = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('test.properties', 'whitespace.end.start'), - COPY('test.properties', 'whitespace.end.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, world!{" "} - ''') - ) - - -class TestConcatLiteral(MockContext): - def setUp(self): - self.strings = parse(DTDParser, ''' - - - - ''') - - def test_concat_literal(self): - msg = FTL.Message( - FTL.Identifier('update-failed'), - value=CONCAT( - COPY('test.properties', 'update.failed.start'), - FTL.TextElement(''), - COPY('test.properties', 'update.failed.linkText'), - FTL.TextElement(''), - COPY('test.properties', 'update.failed.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - update-failed = Update failed. Download manually! - ''') - ) - - -class TestConcatInterpolate(MockContext): - def setUp(self): - self.strings = parse(DTDParser, ''' - - - ''') - - def test_concat_placeable(self): - msg = FTL.Message( - FTL.Identifier('channel-desc'), - value=CONCAT( - COPY('test.properties', 'channel.description.start'), - FTL.Placeable(EXTERNAL_ARGUMENT('channelname')), - COPY('test.properties', 'channel.description.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - channel-desc = You are on the { $channelname } channel. - ''') - ) - - def test_concat_expression(self): - msg = FTL.Message( - FTL.Identifier('channel-desc'), - value=CONCAT( - COPY('test.properties', 'channel.description.start'), - EXTERNAL_ARGUMENT('channelname'), - COPY('test.properties', 'channel.description.end'), - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - channel-desc = You are on the { $channelname } channel. - ''') - ) - - -class TestConcatReplace(MockContext): - def setUp(self): - self.strings = parse(DTDParser, ''' - - - - - - ''') - - def test_concat_replace(self): - msg = FTL.Message( - FTL.Identifier('community'), - value=CONCAT( - REPLACE( - 'test.properties', - 'community.start', - { - '&brandShortName;': MESSAGE_REFERENCE( - 'brand-short-name' - ) - } - ), - FTL.TextElement(''), - REPLACE( - 'test.properties', - 'community.mozillaLink', - { - '&vendorShortName;': MESSAGE_REFERENCE( - 'vendor-short-name' - ) - } - ), - FTL.TextElement(''), - COPY('test.properties', 'community.middle'), - FTL.TextElement(''), - COPY('test.properties', 'community.creditsLink'), - FTL.TextElement(''), - COPY('test.properties', 'community.end') - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json( - 'community = { brand-short-name } is designed by ' - '{ vendor-short-name }, a global community ' - 'working together to…' - ) - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/migrate/test_context.py b/tests/migrate/test_context.py deleted file mode 100644 index cbf19c75..00000000 --- a/tests/migrate/test_context.py +++ /dev/null @@ -1,820 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import os -import logging -import unittest -import compare_locales - -import fluent.syntax.ast as FTL -from fluent.migrate.errors import ( - EmptyLocalizationError, NotSupportedError, UnreadableReferenceError) -from fluent.migrate.util import ftl, ftl_resource_to_json, to_json -from fluent.migrate.context import MergeContext -from fluent.migrate.transforms import CONCAT, COPY - - -def here(*parts): - dirname = os.path.dirname(os.path.realpath(__file__)) - return os.path.join(dirname, *parts) - - -class TestMergeContext_AddTransforms(unittest.TestCase): - def setUp(self): - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def test_hardcoded_node(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('about'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - self.assertSetEqual( - self.ctx.dependencies[(u'aboutDownloads.ftl', u'about')], - set() - ) - self.assertTrue( - self.ctx.in_changeset( - set(), - set(), - 'aboutDownloads.ftl', 'about' - ) - ) - - -class TestMergeContext(unittest.TestCase): - def setUp(self): - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def test_hardcoded_node(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('about'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - about = Hardcoded Value - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_merge_single_message(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - ]) - - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_merge_one_changeset(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.header' - ) - ), - ]) - - changeset = { - ('aboutDownloads.dtd', 'aboutDownloads.title'), - ('aboutDownloads.dtd', 'aboutDownloads.header') - } - - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - header = Twoje pobrane pliki - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset(changeset)), - expected - ) - - def test_merge_two_changesets(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.header' - ) - ), - ]) - - changeset_a = { - ('aboutDownloads.dtd', 'aboutDownloads.title'), - } - - changeset_b = { - ('aboutDownloads.dtd', 'aboutDownloads.header') - } - - expected_a = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - ''') - } - - expected_b = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - header = Twoje pobrane pliki - ''') - } - - merged_a = to_json(self.ctx.merge_changeset(changeset_a)) - self.assertDictEqual(merged_a, expected_a) - - merged_b = to_json(self.ctx.merge_changeset(changeset_b)) - self.assertDictEqual(merged_b, expected_b) - - def test_serialize_changeset(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.header' - ) - ), - ]) - - changesets = [ - { - ('aboutDownloads.dtd', 'aboutDownloads.title'), - }, - { - ('aboutDownloads.dtd', 'aboutDownloads.header') - } - ] - - expected = iter([ - { - 'aboutDownloads.ftl': ftl(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - ''') - }, - { - 'aboutDownloads.ftl': ftl(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - header = Twoje pobrane pliki - ''') - } - ]) - - for changeset in changesets: - serialized = self.ctx.serialize_changeset(changeset) - self.assertEqual(serialized, next(expected)) - - -class TestIncompleteReference(unittest.TestCase): - def setUp(self): - # Silence all logging. - logging.disable(logging.CRITICAL) - - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def tearDown(self): - # Resume logging. - logging.disable(logging.NOTSET) - - def test_missing_reference_file(self): - with self.assertRaises(UnreadableReferenceError): - self.ctx.add_transforms('some.ftl', 'missing.ftl', []) - - -class TestMissingLocalizationFiles(unittest.TestCase): - def setUp(self): - # Silence all logging. - logging.disable(logging.CRITICAL) - - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def tearDown(self): - # Resume logging. - logging.disable(logging.NOTSET) - - def test_missing_file(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'missing.dtd', - 'missing' - ) - ), - ]) - - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_all_files_missing(self): - pattern = ('No localization files were found') - with self.assertRaisesRegexp(EmptyLocalizationError, pattern): - self.ctx.add_transforms('existing.ftl', 'existing.ftl', [ - FTL.Message( - id=FTL.Identifier('foo'), - value=COPY( - 'missing.dtd', - 'foo' - ) - ), - ]) - - -class TestMissingLocalizationStrings(unittest.TestCase): - maxDiff = None - - def setUp(self): - # Silence all logging. - logging.disable(logging.CRITICAL) - - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def tearDown(self): - # Resume logging. - logging.disable(logging.NOTSET) - - def test_missing_string_in_simple_value(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'missing' - ) - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_only_variant(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=CONCAT( - FTL.SelectExpression( - expression=FTL.CallExpression( - callee=FTL.Identifier('PLATFORM') - ), - variants=[ - FTL.Variant( - key=FTL.VariantName('other'), - default=True, - value=COPY( - 'aboutDownloads.dtd', - 'missing' - ) - ), - ] - ), - ) - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_all_variants(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=CONCAT( - FTL.SelectExpression( - expression=FTL.CallExpression( - callee=FTL.Identifier('PLATFORM') - ), - variants=[ - FTL.Variant( - key=FTL.VariantName('windows'), - default=False, - value=COPY( - 'aboutDownloads.dtd', - 'missing.windows' - ) - ), - FTL.Variant( - key=FTL.VariantName('other'), - default=True, - value=COPY( - 'aboutDownloads.dtd', - 'missing.other' - ) - ), - ] - ), - ) - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_one_of_variants(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=CONCAT( - FTL.SelectExpression( - expression=FTL.CallExpression( - callee=FTL.Identifier('PLATFORM') - ), - variants=[ - FTL.Variant( - key=FTL.VariantName('windows'), - default=False, - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Variant( - key=FTL.VariantName('other'), - default=True, - value=COPY( - 'aboutDownloads.dtd', - 'missing.other' - ) - ), - ] - ), - ) - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_only_attribute(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - attributes=[ - FTL.Attribute( - FTL.Identifier('one'), - COPY( - 'aboutDownloads.dtd', - 'missing' - ) - ), - ] - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_all_attributes(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - attributes=[ - FTL.Attribute( - FTL.Identifier('one'), - COPY( - 'aboutDownloads.dtd', - 'missing.one' - ) - ), - FTL.Attribute( - FTL.Identifier('two'), - COPY( - 'aboutDownloads.dtd', - 'missing.two' - ) - ), - ] - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_missing_string_in_one_of_attributes(self): - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - attributes=[ - FTL.Attribute( - FTL.Identifier('title'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Attribute( - FTL.Identifier('missing'), - COPY( - 'aboutDownloads.dtd', - 'missing' - ) - ), - ] - ), - ]) - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - -class TestExistingTarget(unittest.TestCase): - maxDiff = None - - def setUp(self): - # Silence all logging. - logging.disable(logging.CRITICAL) - - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def tearDown(self): - # Resume logging. - logging.disable(logging.NOTSET) - - def test_existing_target_ftl_missing_string(self): - self.ctx.add_transforms('privacy.ftl', 'privacy.ftl', [ - FTL.Message( - id=FTL.Identifier('dnt-learn-more'), - value=COPY( - 'privacy.dtd', - 'doNotTrack.learnMore.label' - ) - ), - ]) - - expected = { - 'privacy.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - dnt-description = New Description in Polish - dnt-learn-more = Więcej informacji - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_existing_target_ftl_existing_string(self): - self.ctx.add_transforms('privacy.ftl', 'privacy.ftl', [ - FTL.Message( - id=FTL.Identifier('dnt-description'), - value=COPY( - 'privacy.dtd', - 'doNotTrack.description' - ) - ), - - # Migrate an extra string to populate the iterator returned by - # ctx.merge_changeset(). Otherwise it won't yield anything if the - # merged contents are the same as the existing file. - FTL.Message( - id=FTL.Identifier('dnt-always'), - value=COPY( - 'privacy.dtd', - 'doNotTrack.always.label' - ) - ), - ]) - - expected = { - 'privacy.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - dnt-description = New Description in Polish - dnt-always = Zawsze - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_existing_target_ftl_with_all_messages(self): - self.ctx.add_transforms('privacy.ftl', 'privacy.ftl', [ - FTL.Message( - id=FTL.Identifier('dnt-description'), - value=COPY( - 'privacy.dtd', - 'doNotTrack.description' - ) - ), - ]) - - # All migrated messages are already in the target FTL and the result of - # merge_changeset is an empty iterator. - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - def test_existing_target_ftl_with_all_messages_reordered(self): - self.ctx.add_transforms('existing.ftl', 'existing.ftl', [ - FTL.Message( - id=FTL.Identifier('foo'), - value=COPY( - 'existing.dtd', - 'foo' - ) - ), - FTL.Message( - id=FTL.Identifier('bar'), - value=COPY( - 'existing.dtd', - 'bar' - ) - ), - ]) - - # All migrated messages are already in the target FTL but in a - # different order. The order of messages is explicitly ignored in the - # snapshot equality check. Consequently, the result of merge_changeset - # is an empty iterator. - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - {} - ) - - -class TestNotSupportedError(unittest.TestCase): - def test_add_ftl(self): - pattern = ('Migrating translations from Fluent files is not supported') - with self.assertRaisesRegexp(NotSupportedError, pattern): - ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - ctx.maybe_add_localization('privacy.ftl') - - -class TestMessagesEqual(unittest.TestCase): - maxDiff = None - - def setUp(self): - # Silence all logging. - logging.disable(logging.CRITICAL) - - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - def tearDown(self): - # Resume logging. - logging.disable(logging.NOTSET) - - def test_messages_equal(self): - first = FTL.Resource([ - FTL.Message( - id=FTL.Identifier('bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - second = FTL.Resource([ - FTL.Message( - id=FTL.Identifier('bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - self.assertTrue(self.ctx.messages_equal(first, second)) - - def test_messages_different_attributes(self): - first = FTL.Resource([ - FTL.Message( - id=FTL.Identifier('bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - second = FTL.Resource([ - FTL.Message( - id=FTL.Identifier('bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]), - attributes=[ - FTL.Attribute( - FTL.Identifier('one'), - value=FTL.Pattern([ - FTL.TextElement('Attribute Value') - ]) - ), - ] - ), - ]) - self.assertFalse(self.ctx.messages_equal(first, second)) - - def test_terms_equal(self): - first = FTL.Resource([ - FTL.Term( - id=FTL.Identifier('-bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - second = FTL.Resource([ - FTL.Term( - id=FTL.Identifier('-bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - self.assertTrue(self.ctx.messages_equal(first, second)) - - def test_terms_different_attributes(self): - first = FTL.Resource([ - FTL.Term( - id=FTL.Identifier('-bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - second = FTL.Resource([ - FTL.Term( - id=FTL.Identifier('-bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]), - attributes=[ - FTL.Attribute( - FTL.Identifier('one'), - value=FTL.Pattern([ - FTL.TextElement('Attribute Value') - ]) - ), - ] - ), - ]) - self.assertFalse(self.ctx.messages_equal(first, second)) - - def test_term_and_message(self): - first = FTL.Resource([ - FTL.Term( - id=FTL.Identifier('-bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - second = FTL.Resource([ - FTL.Message( - id=FTL.Identifier('bar'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - ]) - self.assertFalse(self.ctx.messages_equal(first, second)) diff --git a/tests/migrate/test_context_real_examples.py b/tests/migrate/test_context_real_examples.py deleted file mode 100644 index 3ac83e84..00000000 --- a/tests/migrate/test_context_real_examples.py +++ /dev/null @@ -1,388 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import os -import unittest -import compare_locales - -import fluent.syntax.ast as FTL -from fluent.migrate.util import ftl_resource_to_json, to_json -from fluent.migrate.context import MergeContext -from fluent.migrate.helpers import EXTERNAL_ARGUMENT, MESSAGE_REFERENCE -from fluent.migrate.transforms import ( - CONCAT, COPY, PLURALS, REPLACE_IN_TEXT, REPLACE -) - - -def here(*parts): - dirname = os.path.dirname(os.path.realpath(__file__)) - return os.path.join(dirname, *parts) - - -class TestMergeAboutDownloads(unittest.TestCase): - def setUp(self): - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - self.ctx.add_transforms('aboutDownloads.ftl', 'aboutDownloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.header' - ) - ), - FTL.Message( - id=FTL.Identifier('empty'), - value=COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.empty' - ) - ), - FTL.Message( - id=FTL.Identifier('open-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.open' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('retry-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.retry' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('remove-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.remove' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('pause-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.pause' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('resume-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.resume' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('cancel-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.cancel' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('remove-all-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'aboutDownloads.dtd', - 'aboutDownloads.removeAll' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('delete-all-title'), - value=COPY( - 'aboutDownloads.properties', - 'downloadAction.deleteAll' - ) - ), - FTL.Message( - id=FTL.Identifier('delete-all-message'), - value=PLURALS( - 'aboutDownloads.properties', - 'downloadMessage.deleteAll', - EXTERNAL_ARGUMENT('num'), - lambda text: REPLACE_IN_TEXT( - text, - { - '#1': EXTERNAL_ARGUMENT('num') - } - ) - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-downloading'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.downloading' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-canceled'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.canceled' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-failed'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.failed' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-paused'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.paused' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-starting'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.starting' - ) - ), - FTL.Message( - id=FTL.Identifier('download-size-unknown'), - value=COPY( - 'aboutDownloads.properties', - 'downloadState.unknownSize' - ) - ), - ]) - - def test_merge_context_all_messages(self): - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - header = Twoje pobrane pliki - empty = Brak pobranych plików - - open-menuitem = - .label = Otwórz - retry-menuitem = - .label = Spróbuj ponownie - remove-menuitem = - .label = Usuń - pause-menuitem = - .label = Wstrzymaj - resume-menuitem = - .label = Wznów - cancel-menuitem = - .label = Anuluj - remove-all-menuitem = - .label = Usuń wszystko - - delete-all-title = Usuń wszystko - delete-all-message = - { $num -> - [one] Usunąć pobrany plik? - [few] Usunąć { $num } pobrane pliki? - *[many] Usunąć { $num } pobranych plików? - } - - download-state-downloading = Pobieranie… - download-state-canceled = Anulowane - download-state-failed = Nieudane - download-state-paused = Wstrzymane - download-state-starting = Rozpoczynanie… - download-size-unknown = Nieznany rozmiar - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_merge_context_some_messages(self): - changeset = { - ('aboutDownloads.dtd', 'aboutDownloads.title'), - ('aboutDownloads.dtd', 'aboutDownloads.header'), - ('aboutDownloads.properties', 'downloadState.downloading'), - ('aboutDownloads.properties', 'downloadState.canceled'), - } - - expected = { - 'aboutDownloads.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - title = Pobrane pliki - header = Twoje pobrane pliki - download-state-downloading = Pobieranie… - download-state-canceled = Anulowane - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset(changeset)), - expected - ) - - -class TestMergeAboutDialog(unittest.TestCase): - maxDiff = None - - def setUp(self): - self.ctx = MergeContext( - lang='pl', - reference_dir=here('fixtures/en-US'), - localization_dir=here('fixtures/pl') - ) - - self.ctx.add_transforms('aboutDialog.ftl', 'aboutDialog.ftl', [ - FTL.Message( - id=FTL.Identifier('update-failed'), - value=CONCAT( - COPY('aboutDialog.dtd', 'update.failed.start'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'update.failed.linkText'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'update.failed.end'), - ) - ), - FTL.Message( - id=FTL.Identifier('channel-desc'), - value=CONCAT( - COPY( - 'aboutDialog.dtd', 'channel.description.start' - ), - EXTERNAL_ARGUMENT('channelname'), - COPY('aboutDialog.dtd', 'channel.description.end'), - ) - ), - FTL.Message( - id=FTL.Identifier('community'), - value=CONCAT( - REPLACE( - 'aboutDialog.dtd', - 'community.start', - { - '&brandShortName;': MESSAGE_REFERENCE( - 'brand-short-name' - ) - } - ), - FTL.TextElement(''), - REPLACE( - 'aboutDialog.dtd', - 'community.mozillaLink', - { - '&vendorShortName;': MESSAGE_REFERENCE( - 'vendor-short-name' - ) - } - ), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'community.middle'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'community.creditsLink'), - FTL.TextElement(''), - COPY('aboutDialog.dtd', 'community.end') - ) - ), - ]) - - def test_merge_context_all_messages(self): - expected = { - 'aboutDialog.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - update-failed = Aktualizacja się nie powiodła. Pobierz. - channel-desc = Obecnie korzystasz z kanału { $channelname }.{" "} - community = Program { brand-short-name } został opracowany przez organizację { vendor-short-name }, która jest globalną społecznością, starającą się zapewnić, by… - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset()), - expected - ) - - def test_merge_context_some_messages(self): - changeset = { - ('aboutDialog.dtd', 'update.failed.start'), - ('aboutDialog.dtd', 'update.failed.linkText'), - ('aboutDialog.dtd', 'update.failed.end'), - } - - expected = { - 'aboutDialog.ftl': ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - update-failed = Aktualizacja się nie powiodła. Pobierz. - ''') - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset(changeset)), - expected - ) - - def test_merge_context_too_few_messages(self): - changeset = { - ('aboutDialog.dtd', 'update.failed.start'), - ('aboutDialog.dtd', 'update.failed.linkText'), - } - - self.assertDictEqual( - to_json(self.ctx.merge_changeset(changeset)), - {} - ) diff --git a/tests/migrate/test_copy.py b/tests/migrate/test_copy.py deleted file mode 100644 index ad8fbfee..00000000 --- a/tests/migrate/test_copy.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser, DTDParser - -import fluent.syntax.ast as FTL -from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.transforms import evaluate, COPY - - -class MockContext(unittest.TestCase): - maxDiff = None - - def get_source(self, path, key): - # Ignore path (test.properties) and get translations from self.strings - # defined in setUp. - return self.strings.get(key, None).val - - -class TestCopy(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - foo = Foo - empty = - unicode.all = \\u0020 - unicode.begin1 = \\u0020Foo - unicode.begin2 = \\u0020\\u0020Foo - unicode.end1 = Foo\\u0020 - unicode.end2 = Foo\\u0020\\u0020 - ''') - - def test_copy(self): - msg = FTL.Message( - FTL.Identifier('foo'), - value=COPY('test.properties', 'foo') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - foo = Foo - ''') - ) - - def test_copy_empty(self): - msg = FTL.Message( - FTL.Identifier('empty'), - value=COPY('test.properties', 'empty') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - empty = {""} - ''') - ) - - def test_copy_escape_unicode_all(self): - msg = FTL.Message( - FTL.Identifier('unicode-all'), - value=COPY('test.properties', 'unicode.all') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - unicode-all = {" "} - ''') - ) - - def test_copy_escape_unicode_begin(self): - msg = FTL.Message( - FTL.Identifier('unicode-begin'), - value=COPY('test.properties', 'unicode.begin1') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - unicode-begin = {" "}Foo - ''') - ) - - def test_copy_escape_unicode_begin_many(self): - msg = FTL.Message( - FTL.Identifier('unicode-begin'), - value=COPY('test.properties', 'unicode.begin2') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - unicode-begin = {" "}Foo - ''') - ) - - def test_copy_escape_unicode_end(self): - msg = FTL.Message( - FTL.Identifier('unicode-end'), - value=COPY('test.properties', 'unicode.end1') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - unicode-end = Foo{" "} - ''') - ) - - def test_copy_escape_unicode_end_many(self): - msg = FTL.Message( - FTL.Identifier('unicode-end'), - value=COPY('test.properties', 'unicode.end2') - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - unicode-end = Foo{" "} - ''') - ) - - -class TestCopyAttributes(MockContext): - def setUp(self): - self.strings = parse(DTDParser, ''' - - - - ''') - - def test_copy_accesskey(self): - msg = FTL.Message( - FTL.Identifier('check-for-updates'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY('test.properties', 'checkForUpdatesButton.label') - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'test.properties', 'checkForUpdatesButton.accesskey' - ) - ), - FTL.Attribute( - FTL.Identifier('empty'), - COPY( - 'test.properties', 'checkForUpdatesButton.empty' - ) - ), - ] - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - check-for-updates = - .label = Check for updates - .accesskey = C - .empty = {""} - ''') - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/migrate/test_merge.py b/tests/migrate/test_merge.py deleted file mode 100644 index fbd40398..00000000 --- a/tests/migrate/test_merge.py +++ /dev/null @@ -1,457 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser, DTDParser - -import fluent.syntax.ast as FTL -from fluent.syntax.parser import FluentParser -from fluent.migrate.util import parse, ftl, ftl_resource_to_json -from fluent.migrate.merge import merge_resource -from fluent.migrate.transforms import COPY - - -class MockContext(unittest.TestCase): - def get_source(self, path, key): - # Ignore path (test.properties) and get translations from - # self.ab_cd_legacy defined in setUp. - translation = self.ab_cd_legacy.get(key, None) - - if translation is not None: - return translation.val - - -class TestMergeMessages(MockContext): - maxDiff = None - - def setUp(self): - self.en_us_ftl = parse(FluentParser, ftl(''' - title = Downloads - header = Your Downloads - empty = No Downloads - about = About Downloads - - open-menuitem = - .label = Open - - download-state-downloading = Downloading… - ''')) - - self.ab_cd_ftl = parse(FluentParser, ftl(''' - empty = Brak pobranych plików - about = Previously Hardcoded Value - ''')) - - ab_cd_dtd = parse(DTDParser, ''' - - - ''') - - ab_cd_prop = parse(PropertiesParser, ''' - downloadState.downloading=Pobieranie… - ''') - - self.ab_cd_legacy = { - key: val - for strings in (ab_cd_dtd, ab_cd_prop) - for key, val in strings.items() - } - - self.transforms = [ - FTL.Message( - FTL.Identifier('title'), - value=COPY('test.properties', 'aboutDownloads.title') - ), - FTL.Message( - FTL.Identifier('about'), - value=FTL.Pattern([ - FTL.TextElement('Hardcoded Value') - ]) - ), - FTL.Message( - FTL.Identifier('open-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY('test.properties', 'aboutDownloads.open') - ), - ] - ), - FTL.Message( - FTL.Identifier('download-state-downloading'), - value=COPY('test.properties', 'downloadState.downloading') - ) - ] - - def test_merge_two_way(self): - resource = merge_resource( - self, self.en_us_ftl, FTL.Resource(), self.transforms, - in_changeset=lambda x: True - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - title = Pobrane pliki - about = Hardcoded Value - - open-menuitem = - .label = Otwórz - - download-state-downloading = Pobieranie… - ''') - ) - - def test_merge_three_way(self): - resource = merge_resource( - self, self.en_us_ftl, self.ab_cd_ftl, self.transforms, - in_changeset=lambda x: True - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - title = Pobrane pliki - empty = Brak pobranych plików - about = Previously Hardcoded Value - - open-menuitem = - .label = Otwórz - - download-state-downloading = Pobieranie… - ''') - ) - - -class TestMergeAllEntries(MockContext): - def setUp(self): - self.en_us_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Downloads - header = Your Downloads - empty = No Downloads - - ## Menu items - - # A message comment. - open-menuitem = - .label = Open - - download-state-downloading = Downloading… - ''')) - - self.ab_cd_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - empty = Brak pobranych plików - ''')) - - ab_cd_dtd = parse(DTDParser, ''' - - - ''') - - ab_cd_prop = parse(PropertiesParser, ''' - downloadState.downloading=Pobieranie… - ''') - - self.ab_cd_legacy = { - key: val - for strings in (ab_cd_dtd, ab_cd_prop) - for key, val in strings.items() - } - - self.transforms = [ - FTL.Message( - FTL.Identifier('title'), - value=COPY('test.properties', 'aboutDownloads.title') - ), - FTL.Message( - FTL.Identifier('open-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY('test.properties', 'aboutDownloads.open') - ), - ] - ), - FTL.Message( - FTL.Identifier('download-state-downloading'), - value=COPY('test.properties', 'downloadState.downloading') - ) - ] - - def test_merge_two_way(self): - resource = merge_resource( - self, self.en_us_ftl, FTL.Resource(), self.transforms, - in_changeset=lambda x: True - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - download-state-downloading = Pobieranie… - - ''') - ) - - def test_merge_three_way(self): - resource = merge_resource( - self, self.en_us_ftl, self.ab_cd_ftl, self.transforms, - in_changeset=lambda x: True - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - empty = Brak pobranych plików - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - - download-state-downloading = Pobieranie… - - ''') - ) - - -class TestMergeSubset(MockContext): - def setUp(self): - self.en_us_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Downloads - header = Your Downloads - empty = No Downloads - - ## Menu items - - # A message comment. - open-menuitem = - .label = Open - - download-state-downloading = Downloading… - ''')) - - ab_cd_dtd = parse(DTDParser, ''' - - - ''') - - ab_cd_prop = parse(PropertiesParser, ''' - downloadState.downloading=Pobieranie… - ''') - - self.ab_cd_legacy = { - key: val - for strings in (ab_cd_dtd, ab_cd_prop) - for key, val in strings.items() - } - - self.transforms = [ - FTL.Message( - FTL.Identifier('title'), - value=COPY('test.properties', 'aboutDownloads.title') - ), - FTL.Message( - FTL.Identifier('download-state-downloading'), - value=COPY('test.properties', 'downloadState.downloading') - ) - ] - - def test_two_way_one_entity(self): - subset = ('title',) - resource = merge_resource( - self, self.en_us_ftl, FTL.Resource(), self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - - ## Menu items - ''') - ) - - def test_two_way_two_entities(self): - subset = ('title', 'download-state-downloading') - resource = merge_resource( - self, self.en_us_ftl, FTL.Resource(), self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - - ## Menu items - - download-state-downloading = Pobieranie… - ''') - ) - - def test_three_way_one_entity(self): - ab_cd_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - empty = Brak pobranych plików - ''')) - - subset = ('title',) - resource = merge_resource( - self, self.en_us_ftl, ab_cd_ftl, self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - empty = Brak pobranych plików - - ## Menu items - ''') - ) - - def test_three_way_two_entities(self): - ab_cd_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - empty = Brak pobranych plików - ''')) - - subset = ('title', 'download-state-downloading') - resource = merge_resource( - self, self.en_us_ftl, ab_cd_ftl, self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - empty = Brak pobranych plików - - ## Menu items - - download-state-downloading = Pobieranie… - ''') - ) - - def test_three_way_one_entity_existing_section(self): - ab_cd_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - empty = Brak pobranych plików - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - ''')) - - subset = ('title',) - resource = merge_resource( - self, self.en_us_ftl, ab_cd_ftl, self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - empty = Brak pobranych plików - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - ''') - ) - - def test_three_way_two_entities_existing_section(self): - ab_cd_ftl = parse(FluentParser, ftl(''' - # This Source Code Form is subject to the terms of … - - empty = Brak pobranych plików - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - ''')) - - subset = ('title', 'download-state-downloading') - resource = merge_resource( - self, self.en_us_ftl, ab_cd_ftl, self.transforms, - in_changeset=lambda x: x in subset - ) - - self.assertEqual( - resource.to_json(), - ftl_resource_to_json(''' - # This Source Code Form is subject to the terms of … - - ### A resource comment. - - title = Pobrane pliki - empty = Brak pobranych plików - - ## Menu items - - # A message comment. - open-menuitem = - .label = Otwórz - download-state-downloading = Pobieranie… - ''') - ) diff --git a/tests/migrate/test_plural.py b/tests/migrate/test_plural.py deleted file mode 100644 index 53ef55b2..00000000 --- a/tests/migrate/test_plural.py +++ /dev/null @@ -1,282 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser - -import fluent.syntax.ast as FTL -from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.helpers import EXTERNAL_ARGUMENT -from fluent.migrate.transforms import evaluate, PLURALS, REPLACE_IN_TEXT - - -class MockContext(unittest.TestCase): - maxDiff = None - - def get_source(self, path, key): - # Ignore path (test.properties) and get translations from self.strings - # defined in setUp. - return self.strings.get(key, None).val - - -class TestPlural(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - plural = One;Few;Many - ''') - - self.message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural', - EXTERNAL_ARGUMENT('num') - ) - ) - - def test_plural(self): - self.plural_categories = ('one', 'few', 'many') - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - [few] Few - *[many] Many - } - ''') - ) - - def test_plural_too_few_variants(self): - self.plural_categories = ('one', 'few', 'many', 'other') - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - [few] Few - [many] Many - *[other] Many - } - ''') - ) - - def test_plural_too_many_variants(self): - self.plural_categories = ('one', 'few') - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - *[few] Few - } - ''') - ) - - -class TestPluralOrder(MockContext): - plural_categories = ('one', 'other', 'few') - - def setUp(self): - self.strings = parse(PropertiesParser, ''' - plural = One;Other;Few - ''') - - self.message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural', - EXTERNAL_ARGUMENT('num') - ) - ) - - def test_unordinary_order(self): - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - [few] Few - *[other] Other - } - ''') - ) - - -class TestPluralReplace(MockContext): - plural_categories = ('one', 'few', 'many') - - def setUp(self): - self.strings = parse(PropertiesParser, ''' - plural = One;Few #1;Many #1 - ''') - - def test_plural_replace(self): - msg = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural', - EXTERNAL_ARGUMENT('num'), - lambda text: REPLACE_IN_TEXT( - text, - { - '#1': EXTERNAL_ARGUMENT('num') - } - ) - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - [few] Few { $num } - *[many] Many { $num } - } - ''') - ) - - -class TestNoPlural(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - plural-other = Other - plural-one-other = One;Other - ''') - - def test_one_category_one_variant(self): - self.plural_categories = ('other',) - message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural-other', - EXTERNAL_ARGUMENT('num') - ) - ) - - self.assertEqual( - evaluate(self, message).to_json(), - ftl_message_to_json(''' - plural = Other - ''') - ) - - def test_one_category_many_variants(self): - self.plural_categories = ('other',) - message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural-one-other', - EXTERNAL_ARGUMENT('num') - ) - ) - - self.assertEqual( - evaluate(self, message).to_json(), - ftl_message_to_json(''' - plural = One - ''') - ) - - def test_many_categories_one_variant(self): - self.plural_categories = ('one', 'other') - message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural-other', - EXTERNAL_ARGUMENT('num') - ) - ) - - self.assertEqual( - evaluate(self, message).to_json(), - ftl_message_to_json(''' - plural = Other - ''') - ) - - -class TestEmpty(MockContext): - plural_categories = ('one', 'few', 'many') - - def setUp(self): - self.message = FTL.Message( - FTL.Identifier('plural'), - value=PLURALS( - 'test.properties', - 'plural', - EXTERNAL_ARGUMENT('num') - ) - ) - - def test_non_default_empty(self): - self.strings = parse(PropertiesParser, ''' - plural = ;Few;Many - ''') - - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [few] Few - *[many] Many - } - ''') - ) - - def test_default_empty(self): - self.strings = parse(PropertiesParser, ''' - plural = One;Few; - ''') - - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = - { $num -> - [one] One - [few] Few - *[many] Few - } - ''') - ) - - def test_all_empty(self): - self.strings = parse(PropertiesParser, ''' - plural = ; - ''') - - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = {""} - ''') - ) - - def test_no_value(self): - self.strings = parse(PropertiesParser, ''' - plural = - ''') - - self.assertEqual( - evaluate(self, self.message).to_json(), - ftl_message_to_json(''' - plural = {""} - ''') - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/migrate/test_replace.py b/tests/migrate/test_replace.py deleted file mode 100644 index 18449f4f..00000000 --- a/tests/migrate/test_replace.py +++ /dev/null @@ -1,236 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser - -import fluent.syntax.ast as FTL -from fluent.migrate.util import parse, ftl_message_to_json -from fluent.migrate.helpers import EXTERNAL_ARGUMENT -from fluent.migrate.transforms import evaluate, REPLACE - - -class MockContext(unittest.TestCase): - maxDiff = None - - def get_source(self, path, key): - # Ignore path (test.properties) and get translations from self.strings - # defined in setUp. - return self.strings.get(key, None).val - - -class TestReplace(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - empty = - hello = Hello, #1! - welcome = Welcome, #1, to #2! - first = #1 Bar - last = Foo #1 - ''') - - def test_replace_empty(self): - msg = FTL.Message( - FTL.Identifier(u'empty'), - value=REPLACE( - 'test.properties', - 'empty', - { - '#1': EXTERNAL_ARGUMENT('arg') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - empty = {""} - ''') - ) - - def test_replace_one(self): - msg = FTL.Message( - FTL.Identifier(u'hello'), - value=REPLACE( - 'test.properties', - 'hello', - { - '#1': EXTERNAL_ARGUMENT('username') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, { $username }! - ''') - ) - - def test_replace_two(self): - msg = FTL.Message( - FTL.Identifier(u'welcome'), - value=REPLACE( - 'test.properties', - 'welcome', - { - '#1': EXTERNAL_ARGUMENT('username'), - '#2': EXTERNAL_ARGUMENT('appname') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - welcome = Welcome, { $username }, to { $appname }! - ''') - ) - - def test_replace_too_many(self): - msg = FTL.Message( - FTL.Identifier(u'welcome'), - value=REPLACE( - 'test.properties', - 'welcome', - { - '#1': EXTERNAL_ARGUMENT('username'), - '#2': EXTERNAL_ARGUMENT('appname'), - '#3': EXTERNAL_ARGUMENT('extraname') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - welcome = Welcome, { $username }, to { $appname }! - ''') - ) - - def test_replace_too_few(self): - msg = FTL.Message( - FTL.Identifier(u'welcome'), - value=REPLACE( - 'test.properties', - 'welcome', - { - '#1': EXTERNAL_ARGUMENT('username') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - welcome = Welcome, { $username }, to #2! - ''') - ) - - def test_replace_first(self): - msg = FTL.Message( - FTL.Identifier(u'first'), - value=REPLACE( - 'test.properties', - 'first', - { - '#1': EXTERNAL_ARGUMENT('foo') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - first = { $foo } Bar - ''') - ) - - def test_replace_last(self): - msg = FTL.Message( - FTL.Identifier(u'last'), - value=REPLACE( - 'test.properties', - 'last', - { - '#1': EXTERNAL_ARGUMENT('bar') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - last = Foo { $bar } - ''') - ) - - def test_replace_with_placeable(self): - msg = FTL.Message( - FTL.Identifier(u'hello'), - value=REPLACE( - 'test.properties', - 'hello', - { - '#1': FTL.Placeable( - EXTERNAL_ARGUMENT('user') - ) - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, { $user }! - ''') - ) - - def test_replace_with_text_element(self): - msg = FTL.Message( - FTL.Identifier(u'hello'), - value=REPLACE( - 'test.properties', - 'hello', - { - '#1': FTL.TextElement('you') - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, you! - ''') - ) - - def test_replace_with_pattern(self): - msg = FTL.Message( - FTL.Identifier(u'hello'), - value=REPLACE( - 'test.properties', - 'hello', - { - '#1': FTL.Pattern( - elements=[ - FTL.TextElement(' '), - FTL.Placeable( - EXTERNAL_ARGUMENT('user') - ) - ] - ) - } - ) - ) - - self.assertEqual( - evaluate(self, msg).to_json(), - ftl_message_to_json(''' - hello = Hello, { $user }! - ''') - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/migrate/test_source.py b/tests/migrate/test_source.py deleted file mode 100644 index 7f124d2a..00000000 --- a/tests/migrate/test_source.py +++ /dev/null @@ -1,194 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest -from compare_locales.parser import PropertiesParser, DTDParser - -import fluent.syntax.ast as FTL -from fluent.migrate.errors import NotSupportedError -from fluent.migrate.transforms import Source, COPY, PLURALS, REPLACE -from fluent.migrate.util import parse -from fluent.migrate.helpers import EXTERNAL_ARGUMENT - - -class TestNotSupportedError(unittest.TestCase): - def test_source(self): - pattern = ('Migrating translations from Fluent files is not supported') - with self.assertRaisesRegexp(NotSupportedError, pattern): - Source('test.ftl', 'foo') - - def test_copy(self): - pattern = ('Migrating translations from Fluent files is not supported') - with self.assertRaisesRegexp(NotSupportedError, pattern): - FTL.Message( - FTL.Identifier('foo'), - value=COPY('test.ftl', 'foo') - ) - - def test_plurals(self): - pattern = ('Migrating translations from Fluent files is not supported') - with self.assertRaisesRegexp(NotSupportedError, pattern): - FTL.Message( - FTL.Identifier('delete-all'), - value=PLURALS( - 'test.ftl', - 'deleteAll', - EXTERNAL_ARGUMENT('num') - ) - ) - - def test_replace(self): - pattern = ('Migrating translations from Fluent files is not supported') - with self.assertRaisesRegexp(NotSupportedError, pattern): - FTL.Message( - FTL.Identifier(u'hello'), - value=REPLACE( - 'test.ftl', - 'hello', - { - '#1': EXTERNAL_ARGUMENT('username') - } - ) - ) - - -class MockContext(unittest.TestCase): - def get_source(self, _path, key): - # Ignore _path (test.properties) and get translations from self.strings. - return self.strings[key].val - - -class TestProperties(MockContext): - def setUp(self): - self.strings = parse(PropertiesParser, ''' - foo = Foo - value-empty = - value-whitespace = - - unicode-all = \\u0020 - unicode-start = \\u0020Foo - unicode-middle = Foo\\u0020Bar - unicode-end = Foo\\u0020 - - html-entity = <⇧⌘K> - ''') - - def test_simple_text(self): - source = Source('test.properties', 'foo') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, 'Foo') - - def test_empty_value(self): - source = Source('test.properties', 'value-empty') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '') - - def test_whitespace_value(self): - source = Source('test.properties', 'value-whitespace') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '') - - def test_escape_unicode_all(self): - source = Source('test.properties', 'unicode-all') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, ' ') - - def test_escape_unicode_start(self): - source = Source('test.properties', 'unicode-start') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, ' Foo') - - def test_escape_unicode_middle(self): - source = Source('test.properties', 'unicode-middle') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, 'Foo Bar') - - def test_escape_unicode_end(self): - source = Source('test.properties', 'unicode-end') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, 'Foo ') - - def test_html_entity(self): - source = Source('test.properties', 'html-entity') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '<⇧⌘K>') - - -class TestDTD(MockContext): - def setUp(self): - self.strings = parse(DTDParser, ''' - - - - - - - - - - - - - ''') - - def test_simple_text(self): - source = Source('test.dtd', 'foo') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, 'Foo') - - def test_empty_value(self): - source = Source('test.dtd', 'valueEmpty') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '') - - def test_whitespace_value(self): - source = Source('test.dtd', 'valueWhitespace') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, ' ') - - def test_backslash_unicode_escape(self): - source = Source('test.dtd', 'unicodeEscape') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, 'Foo\\u0020Bar') - - def test_named_entity(self): - source = Source('test.dtd', 'named') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '&') - - def test_decimal_entity(self): - source = Source('test.dtd', 'decimal') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '&') - - def test_shorthex_entity(self): - source = Source('test.dtd', 'shorthexcode') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '&') - - def test_longhex_entity(self): - source = Source('test.dtd', 'longhexcode') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '&') - - def test_unknown_entity(self): - source = Source('test.dtd', 'unknown') - element = source(self) - self.assertIsInstance(element, FTL.TextElement) - self.assertEqual(element.value, '&unknownEntity;') diff --git a/tests/migrate/test_util.py b/tests/migrate/test_util.py deleted file mode 100644 index 40a81df3..00000000 --- a/tests/migrate/test_util.py +++ /dev/null @@ -1,100 +0,0 @@ -# coding=utf8 -from __future__ import unicode_literals - -import unittest - -import fluent.syntax.ast as FTL -from fluent.util import fold -from fluent.migrate.transforms import CONCAT, COPY, REPLACE, Source - - -def get_source(acc, cur): - if isinstance(cur, Source): - return acc + ((cur.path, cur.key),) - return acc - - -class TestTraverse(unittest.TestCase): - def test_copy_concat(self): - node = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('path1', 'key1'), - COPY('path2', 'key2') - ) - ) - - result = node.traverse(lambda x: x) - - self.assertEqual( - result.value.elements[0].key, - 'key1' - ) - self.assertEqual( - result.value.elements[1].key, - 'key2' - ) - - -class TestReduce(unittest.TestCase): - def test_copy_value(self): - node = FTL.Message( - id=FTL.Identifier('key'), - value=COPY('path', 'key') - ) - - self.assertEqual( - fold(get_source, node, ()), - (('path', 'key'),) - ) - - def test_copy_traits(self): - node = FTL.Message( - id=FTL.Identifier('key'), - attributes=[ - FTL.Attribute( - FTL.Identifier('trait1'), - value=COPY('path1', 'key1') - ), - FTL.Attribute( - FTL.Identifier('trait2'), - value=COPY('path2', 'key2') - ) - ] - ) - - self.assertEqual( - fold(get_source, node, ()), - (('path1', 'key1'), ('path2', 'key2')) - ) - - def test_copy_concat(self): - node = FTL.Message( - FTL.Identifier('hello'), - value=CONCAT( - COPY('path1', 'key1'), - COPY('path2', 'key2') - ) - ) - - self.assertEqual( - fold(get_source, node, ()), - (('path1', 'key1'), ('path2', 'key2')) - ) - - def test_copy_in_replace(self): - node = FTL.Message( - FTL.Identifier('hello'), - value=REPLACE( - 'path1', - 'key1', - { - "foo": COPY('path2', 'key2') - } - ) - ) - - self.assertEqual( - fold(get_source, node, ()), - (('path2', 'key2'), ('path1', 'key1')) - ) diff --git a/tools/migrate/README.md b/tools/migrate/README.md deleted file mode 100644 index 9e52cb46..00000000 --- a/tools/migrate/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Migration Tools - -`migrate-l10n.py` is a CLI script which uses the `fluent.migrate` module under -the hood to run migrations on existing translations. - -## Examples - -The `examples/` directory contains a number of sample migrations. To run them -you'll need at least one clone of a localization repository, e.g. from -https://hg.mozilla.org/l10n-central/. - -Amend your `PYTHONPATH` to make sure that all `fluent.*` modules can be found: - - $ export PYTHONPATH=$(pwd)/../..:$PYTHONPATH - -Then run migrations passing the `examples` directory as the reference: - - $ ./migrate-l10n.py --lang it --reference-dir examples --localization-dir ~/moz/l10n-central/it examples.about_dialog examples.about_downloads examples.bug_1291693 - -Here's what the output should look like: - - Annotating /home/stas/moz/l10n-central/it - Running migration examples.bug_1291693 - Writing to /home/stas/moz/l10n-central/it/browser/branding/official/brand.ftl - Committing changeset: Bug 1291693 - Migrate the menubar to FTL, part 1 - Writing to /home/stas/moz/l10n-central/it/browser/menubar.ftl - Writing to /home/stas/moz/l10n-central/it/browser/toolbar.ftl - Writing to /home/stas/moz/l10n-central/it/browser/branding/official/brand.ftl - Committing changeset: Bug 1291693 - Migrate the menubar to FTL, part 2 - Running migration examples.about_dialog - Writing to /home/stas/moz/l10n-central/it/browser/about_dialog.ftl - Committing changeset: Migrate about:dialog, part 1 - Running migration examples.about_downloads - Writing to /home/stas/moz/l10n-central/it/mobile/about_downloads.ftl - Committing changeset: Migrate about:download in Firefox for Android, part 1 - Writing to /home/stas/moz/l10n-central/it/mobile/about_downloads.ftl - Committing changeset: Migrate about:download in Firefox for Android, part 2 - Writing to /home/stas/moz/l10n-central/it/mobile/about_downloads.ftl - Committing changeset: Migrate about:download in Firefox for Android, part 3 diff --git a/tools/migrate/blame.py b/tools/migrate/blame.py deleted file mode 100644 index 0afa4fbf..00000000 --- a/tools/migrate/blame.py +++ /dev/null @@ -1,64 +0,0 @@ -import argparse -import json -import os - -from compare_locales.parser import getParser, Junk -import hglib -from hglib.util import b, cmdbuilder - - -class Blame(object): - def __init__(self, client): - self.client = client - self.users = [] - self.blame = {} - - def attribution(self, file_paths): - args = cmdbuilder( - b('annotate'), *map(b, file_paths), template='json', - date=True, user=True, cwd=self.client.root()) - blame_json = ''.join(self.client.rawcommand(args)) - file_blames = json.loads(blame_json) - - for file_blame in file_blames: - self.handleFile(file_blame) - - return {'authors': self.users, - 'blame': self.blame} - - def handleFile(self, file_blame): - path = file_blame['path'] - - try: - parser = getParser(path) - except UserWarning: - return - - self.blame[path] = {} - - parser.readFile(os.path.join(self.client.root(), path)) - entities, emap = parser.parse() - for e in entities: - if isinstance(e, Junk): - continue - entity_lines = file_blame['lines'][ - (e.value_position()[0] - 1):e.value_position(-1)[0] - ] - # ignore timezone - entity_lines.sort(key=lambda blame: -blame['date'][0]) - line_blame = entity_lines[0] - user = line_blame['user'] - timestamp = line_blame['date'][0] # ignore timezone - if user not in self.users: - self.users.append(user) - userid = self.users.index(user) - self.blame[path][e.key] = [userid, timestamp] - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('repo_path') - parser.add_argument('file_path', nargs='+') - args = parser.parse_args() - blame = Blame(hglib.open(args.repo_path)) - attrib = blame.attribution(args.file_path) - print(json.dumps(attrib, indent=4, separators=(',', ': '))) diff --git a/tools/migrate/examples/__init__.py b/tools/migrate/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/migrate/examples/about_dialog.ftl b/tools/migrate/examples/about_dialog.ftl deleted file mode 100644 index 21901565..00000000 --- a/tools/migrate/examples/about_dialog.ftl +++ /dev/null @@ -1,12 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -update-failed = - Update failed. -channel-description = - You are currently on the update channel. -community = - { brand-short-name } is designed by , - a working together to keep the Web - open, public and accessible to all. diff --git a/tools/migrate/examples/about_dialog.py b/tools/migrate/examples/about_dialog.py deleted file mode 100644 index 7afd7d91..00000000 --- a/tools/migrate/examples/about_dialog.py +++ /dev/null @@ -1,84 +0,0 @@ -# coding=utf8 - -import fluent.syntax.ast as FTL -from fluent.migrate import CONCAT, COPY, REPLACE -from fluent.migrate.helpers import EXTERNAL_ARGUMENT, MESSAGE_REFERENCE - - -def migrate(ctx): - """Migrate about:dialog, part {index}""" - - ctx.add_transforms('browser/about_dialog.ftl', 'about_dialog.ftl', [ - FTL.Message( - id=FTL.Identifier('update-failed'), - value=CONCAT( - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'update.failed.start' - ), - FTL.TextElement(''), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'update.failed.linkText' - ), - FTL.TextElement(''), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'update.failed.end' - ) - ) - ), - FTL.Message( - id=FTL.Identifier('channel-description'), - value=CONCAT( - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'channel.description.start' - ), - FTL.Placeable(EXTERNAL_ARGUMENT('channelname')), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'channel.description.end' - ) - ) - ), - FTL.Message( - id=FTL.Identifier('community'), - value=CONCAT( - REPLACE( - 'browser/chrome/browser/aboutDialog.dtd', - 'community.start2', - { - '&brandShortName;': MESSAGE_REFERENCE( - 'brand-short-name' - ) - } - ), - FTL.TextElement(''), - REPLACE( - 'browser/chrome/browser/aboutDialog.dtd', - 'community.mozillaLink', - { - '&vendorShortName;': MESSAGE_REFERENCE( - 'vendor-short-name' - ) - } - ), - FTL.TextElement(''), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'community.middle2' - ), - FTL.TextElement(''), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'community.creditsLink' - ), - FTL.TextElement(''), - COPY( - 'browser/chrome/browser/aboutDialog.dtd', - 'community.end3' - ) - ) - ), - ]) diff --git a/tools/migrate/examples/about_downloads.ftl b/tools/migrate/examples/about_downloads.ftl deleted file mode 100644 index e591eee8..00000000 --- a/tools/migrate/examples/about_downloads.ftl +++ /dev/null @@ -1,38 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -title = Downloads -header = Your Downloads -empty = No Downloads - -open-menuitem - .label = Open -retry-menuitem - .label = Retry -remove-menuitem - .label = Delete -pause-menuitem - .label = Pause -resume-menuitem - .label = Resume -cancel-menuitem - .label = Cancel -remove-all-menuitem - .label = Delete All - -delete-all-title = Delete All -delete-all-message = - { $num -> - [1] Delete this download? - *[other] Delete { $num } downloads? - } - -download-state-downloading = Downloading… -download-state-canceled = Canceled -download-state-failed = Failed -download-state-paused = Paused -download-state-starting = Starting… -download-state-unknown = Unknown - -download-size-unknown = Unknown size diff --git a/tools/migrate/examples/about_downloads.py b/tools/migrate/examples/about_downloads.py deleted file mode 100644 index a07d9b0a..00000000 --- a/tools/migrate/examples/about_downloads.py +++ /dev/null @@ -1,180 +0,0 @@ -# coding=utf8 - -import fluent.syntax.ast as FTL -from fluent.migrate import COPY, PLURALS, REPLACE_IN_TEXT -from fluent.migrate.helpers import EXTERNAL_ARGUMENT - - -def migrate(ctx): - """Migrate about:download in Firefox for Android, part {index}""" - - ctx.add_transforms('mobile/about_downloads.ftl', 'about_downloads.ftl', [ - FTL.Message( - id=FTL.Identifier('title'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.title' - ) - ), - FTL.Message( - id=FTL.Identifier('header'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.header' - ) - ), - FTL.Message( - id=FTL.Identifier('empty'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.empty' - ) - ), - FTL.Message( - id=FTL.Identifier('open-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.open' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('retry-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.retry' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('remove-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.remove' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('pause-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.pause' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('resume-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.resume' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('cancel-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.cancel' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('remove-all-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'mobile/android/chrome/aboutDownloads.dtd', - 'aboutDownloads.removeAll' - ) - ) - ] - ), - FTL.Message( - id=FTL.Identifier('delete-all-title'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadAction.deleteAll' - ) - ), - FTL.Message( - id=FTL.Identifier('delete-all-message'), - value=PLURALS( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadMessage.deleteAll', - EXTERNAL_ARGUMENT('num'), - lambda text: REPLACE_IN_TEXT( - text, - { - '#1': EXTERNAL_ARGUMENT('num') - } - ) - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-downloading'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.downloading' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-canceled'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.canceled' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-failed'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.failed' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-paused'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.paused' - ) - ), - FTL.Message( - id=FTL.Identifier('download-state-starting'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.starting' - ) - ), - FTL.Message( - id=FTL.Identifier('download-size-unknown'), - value=COPY( - 'mobile/android/chrome/aboutDownloads.properties', - 'downloadState.unknownSize' - ) - ), - ]) diff --git a/tools/migrate/examples/brand.ftl b/tools/migrate/examples/brand.ftl deleted file mode 100644 index f9aae63e..00000000 --- a/tools/migrate/examples/brand.ftl +++ /dev/null @@ -1,13 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -brand-shorter-name = Firefox -brand-short-name = Firefox -brand-full-name = Mozilla Firefox -vendor-short-name = Mozilla - -trademark-info = - Firefox and the Firefox logos are trademarks of the Mozilla Foundation. - -sync-brand-short-name = Sync diff --git a/tools/migrate/examples/bug_1291693.py b/tools/migrate/examples/bug_1291693.py deleted file mode 100644 index 6fd27c45..00000000 --- a/tools/migrate/examples/bug_1291693.py +++ /dev/null @@ -1,1918 +0,0 @@ -# coding=utf8 - -import fluent.syntax.ast as FTL -from fluent.migrate import COPY, REPLACE -from fluent.migrate.helpers import MESSAGE_REFERENCE - - -def migrate(ctx): - """Bug 1291693 - Migrate the menubar to FTL, part {index}""" - - ctx.add_transforms('browser/menubar.ftl', 'menubar.ftl', [ - FTL.Message( - id=FTL.Identifier('file-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fileMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fileMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('tab-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'tabCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'tabCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('tab-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'tabCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('new-user-context-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newUserContext.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newUserContext.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('new-navigator-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newNavigatorCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newNavigatorCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('new-navigator-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newNavigatorCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('new-private-window-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newPrivateWindow.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newPrivateWindow.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('new-non-remote-window-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'newNonRemoteWindow.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('open-location-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'openLocationCmd.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('open-file-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'openFileCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'openFileCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('open-file-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'openFileCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('close-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'closeCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'closeCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('close-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'closeCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('close-window-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'closeWindow.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'closeWindow.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('save-page-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'savePageCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'savePageCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('save-page-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'savePageCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('email-page-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'emailPageCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'emailPageCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('print-setup-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printSetupCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printSetupCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('print-preview-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printPreviewCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printPreviewCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('print-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('print-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'printCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('go-offline-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'goOfflineCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'goOfflineCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('quit-application-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('quit-application-menuitem-win'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmdWin2.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmdWin2.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('quit-application-menuitem-mac'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmdMac2.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('quit-application-command-unix'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'quitApplicationCmdUnix.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('edit-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'editMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'editMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('undo-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'undoCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'undoCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('undo-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'undoCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('redo-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'redoCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'redoCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('redo-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'redoCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('cut-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'cutCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'cutCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('cut-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'cutCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('copy-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'copyCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'copyCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('copy-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'copyCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('paste-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pasteCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pasteCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('paste-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pasteCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('delete-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'deleteCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'deleteCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('select-all-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'selectAllCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'selectAllCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('select-all-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'selectAllCmd.key', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-on-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findOnCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findOnCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-on-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findOnCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-again-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findAgainCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findAgainCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-again-command1'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findAgainCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-again-command2'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findAgainCmd.commandkey2', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('find-selection-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'findSelectionCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bidi-switch-text-direction-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bidiSwitchTextDirectionItem.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bidiSwitchTextDirectionItem.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bidi-switch-text-direction-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bidiSwitchTextDirectionItem.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('preferences-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'preferencesCmd2.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'preferencesCmd2.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('preferences-menuitem-unix'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'preferencesCmdUnix.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'preferencesCmdUnix.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-toolbar-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewToolbarsMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewToolbarsMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-sidebar-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewSidebarMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewSidebarMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-customize-toolbar-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewCustomizeToolbar.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'viewCustomizeToolbar.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoom.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoom.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-enlarge-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomEnlargeCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomEnlargeCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-enlarge-command1'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomEnlargeCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-enlarge-command2'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomEnlargeCmd.commandkey2', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-enlarge-command3'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomEnlargeCmd.commandkey3', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reduce-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomReduceCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomReduceCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reduce-command1'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomReduceCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reduce-command2'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomReduceCmd.commandkey2', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reset-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomResetCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomResetCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reset-command1'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomResetCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-reset-command2'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomResetCmd.commandkey2', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-zoom-toggle-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomToggleCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullZoomToggleCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-style-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStyleMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStyleMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-style-no-style-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStyleNoStyle.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStyleNoStyle.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-style-persistent-only-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStylePersistentOnly.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageStylePersistentOnly.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-tabs-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'showAllTabsCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'showAllTabsCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bidi-switch-page-direction-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bidiSwitchPageDirectionItem.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bidiSwitchPageDirectionItem.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('enter-full-screen-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'enterFullScreenCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'enterFullScreenCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('exit-full-screen-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'exitFullScreenCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'exitFullScreenCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-screen-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullScreenCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullScreenCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('full-screen-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'fullScreenCmd.macCommandKey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('history-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-history-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'showAllHistoryCmd2.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-history-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'showAllHistoryCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('clear-recent-history-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'clearRecentHistory.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('history-synced-tabs-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncTabsMenu3.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('history-restore-last-session-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyRestoreLastSession.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('history-undo-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyUndoMenu.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('history-undo-window-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyUndoWindowMenu.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bookmarks-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-bookmarks-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'showAllBookmarks2.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-bookmarks-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('show-all-bookmarks-command-gtk'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksGtkCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bookmark-this-page-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarkThisPageCmd.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('edit-this-page-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'editThisBookmarkCmd.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('bookmark-this-page-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarkThisPageCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('subscribe-to-page-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'subscribeToPageMenupopup.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('subscribe-to-page-menupopup'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'subscribeToPageMenupopup.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('add-cur-pages-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'addCurPagesCmd.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('recent-bookmarks-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'recentBookmarks.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('other-bookmarks-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'otherBookmarksCmd.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('personalbar-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'personalbarCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'personalbarCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('tools-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'toolsMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'toolsMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('downloads-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'downloads.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'downloads.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('downloads-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'downloads.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('downloads-command-unix'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'downloadsUnix.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('addons-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'addons.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'addons.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('addons-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'addons.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('sync-sign-in-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - REPLACE( - 'browser/chrome/browser/browser.dtd', - 'syncSignIn.label', - { - '&syncBrand.shortName.label;': MESSAGE_REFERENCE( - 'sync-brand-short-name' - ) - } - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncSignIn.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('sync-sync-now-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncSyncNowItem.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncSyncNowItem.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('sync-re-auth-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - REPLACE( - 'browser/chrome/browser/browser.dtd', - 'syncReAuthItem.label', - { - '&syncBrand.shortName.label;': MESSAGE_REFERENCE( - 'sync-brand-short-name' - ) - } - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncReAuthItem.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('sync-toolbar-button'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncToolbarButton.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('web-developer-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'webDeveloperMenu.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'webDeveloperMenu.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-source-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageSourceCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageSourceCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-source-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageSourceCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-info-menuitem'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageInfoCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageInfoCmd.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('page-info-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'pageInfoCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('mirror-tab-menu'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'mirrorTabCmd.label', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'mirrorTabCmd.accesskey', - ) - ), - ] - ), - ]) - - ctx.add_transforms('browser/toolbar.ftl', 'toolbar.ftl', [ - FTL.Message( - id=FTL.Identifier('urlbar-textbox'), - attributes=[ - FTL.Attribute( - FTL.Identifier('placeholder'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'urlbar.placeholder2', - ) - ), - FTL.Attribute( - FTL.Identifier('accesskey'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'urlbar.accesskey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-bookmarks-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksButton.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-bookmarks-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-bookmarks-command-win'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'bookmarksWinCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-history-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historyButton.label', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-history-command'), - attributes=[ - FTL.Attribute( - FTL.Identifier('key'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'historySidebarCmd.commandkey', - ) - ), - ] - ), - FTL.Message( - id=FTL.Identifier('view-tabs-broadcaster'), - attributes=[ - FTL.Attribute( - FTL.Identifier('label'), - COPY( - 'browser/chrome/browser/browser.dtd', - 'syncedTabs.sidebar.label', - ) - ), - ] - ), - ]) - - ctx.add_transforms('browser/branding/official/brand.ftl', 'brand.ftl', [ - FTL.Message( - id=FTL.Identifier('brand-shorter-name'), - value=COPY( - 'browser/branding/official/brand.dtd', - 'brandShorterName' - ) - ), - FTL.Message( - id=FTL.Identifier('brand-short-name'), - value=COPY( - 'browser/branding/official/brand.dtd', - 'brandShortName' - ) - ), - FTL.Message( - id=FTL.Identifier('brand-full-name'), - value=COPY( - 'browser/branding/official/brand.dtd', - 'brandFullName' - ) - ), - FTL.Message( - id=FTL.Identifier('vendor-short-name'), - value=COPY( - 'browser/branding/official/brand.dtd', - 'vendorShortName' - ) - ), - FTL.Message( - id=FTL.Identifier('trademark-info'), - value=COPY( - 'browser/branding/official/brand.dtd', - 'trademarkInfo.part1' - ) - ), - FTL.Message( - id=FTL.Identifier('sync-brand-short-name'), - value=COPY( - 'browser/branding/official/brand.properties', - 'syncBrandShortName' - ) - ), - ]) diff --git a/tools/migrate/examples/menubar.ftl b/tools/migrate/examples/menubar.ftl deleted file mode 100644 index c4a2ab59..00000000 --- a/tools/migrate/examples/menubar.ftl +++ /dev/null @@ -1,336 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -[[ File menu ]] - -file-menu - .label = File - .accesskey = F -tab-menuitem - .label = New Tab - .accesskey = T -tab-command - .key = t -new-user-context-menu - .label = New Container Tab - .accesskey = C -new-navigator-menuitem - .label = New Window - .accesskey = N -new-navigator-command - .key = N -new-private-window-menuitem - .label = New Private Window - .accesskey = W -new-non-remote-window-menuitem - .label = New Non-e10s Window - -// Only displayed on OS X, and only on windows that aren't main browser windows, -// or when there are no windows but Firefox is still running. -open-location-menuitem - .label = Open Location… -open-file-menuitem - .label = Open File… - .accesskey = O -open-file-command - .key = o - -close-menuitem - .label = Close - .accesskey = C -close-command - .key = W -close-window-menuitem - .label = Close Window - .accesskey = d - -// .accesskey2 is for content area context menu -save-page-menuitem - .label = Save Page As… - .accesskey = A - .accesskey2 = P -save-page-command - .key = s - -email-page-menuitem - .label = Email Link… - .accesskey = E - -print-setup-menuitem - .label = Page Setup… - .accesskey = u -print-preview-menuitem - .label = Print Preview… - .accesskey = v -print-menuitem - .label = Print… - .accesskey = P -print-command - .key = p - -go-offline-menuitem - .label = Work Offline - .accesskey = k - -quit-application-menuitem - .label = Quit - .accesskey = Q -quit-application-menuitem-win - .label = Exit - .accesskey = x -quit-application-menuitem-mac - .label = Quit { brand-shorter-name } -// Used by both Linux and OSX builds -quit-application-command-unix - .key = Q - -[[ Edit menu ]] - -edit-menu - .label = Edit - .accesskey = E -undo-menuitem - .label = Undo - .accesskey = U -undo-command - .key = Z -redo-menuitem - .label = Redo - .accesskey = R -redo-command - .key = Y -cut-menuitem - .label = Cut - .accesskey = t -cut-command - .key = X -copy-menuitem - .label = Copy - .accesskey = C -copy-command - .key = C -paste-menuitem - .label = Paste - .accesskey = P -paste-command - .key = V -delete-menuitem - .label = Delete - .accesskey = D -select-all-menuitem - .label = Select All - .accesskey = A -select-all-command - .key = A - -find-on-menuitem - .label = Find in This Page… - .accesskey = F -find-on-command - .key = f -find-again-menuitem - .label = Find Again - .accesskey = g -find-again-command1 - .key = g -find-again-command2 - .keycode = VK_F3 -find-selection-command - .key = e - -bidi-switch-text-direction-menuitem - .label = Switch Text Direction - .accesskey = w -bidi-switch-text-direction-command - .key = X - -preferences-menuitem - .label = Options - .accesskey = O -preferences-menuitem-unix - .label = Preferences - .accesskey = n - - -[[ View menu ]] - -view-menu - .label = View - .accesskey = V -view-toolbars-menu - .label = Toolbars - .accesskey = T -view-sidebar-menu - .label = Sidebar - .accesskey = e -view-customize-toolbar-menuitem - .label = Customize… - .accesskey = C - -full-zoom-menu - .label = Zoom - .accesskey = Z -full-zoom-enlarge-menuitem - .label = Zoom In - .accesskey = I -full-zoom-enlarge-command1 - .key = + -full-zoom-enlarge-command2 - .key = -full-zoom-enlarge-command3 - .key = "" -full-zoom-reduce-menuitem - .label = Zoom Out - .accesskey = O -full-zoom-reduce-command1 - .key = - -full-zoom-reduce-command2 - .key = "" -full-zoom-reset-menuitem - .label = Reset - .accesskey = R -full-zoom-reset-command1 - .key = 0 -full-zoom-reset-command2 - .key = "" -full-zoom-toggle-menuitem - .label = Zoom Text Only - .accesskey = T - -page-style-menu - .label = Page Style - .accesskey = y -page-style-no-style-menuitem - .label = No Style - .accesskey = n -page-style-persistent-only-menuitem - .label = Basic Page Style - .accesskey = b - -show-all-tabs-menuitem - .label = Show All Tabs - .accesskey = A -bidi-switch-page-direction-menuitem - .label = Switch Page Direction - .accesskey = D - -// Match what Safari and other Apple applications use on OS X Lion. -[[ Full Screen controls ]] - -enter-full-screen-menuitem - .label = Enter Full Screen - .accesskey = F -exit-full-screen-menuitem - .label = Exit Full Screen - .accesskey = F -full-screen-menuitem - .label = Full Screen - .accesskey = F -full-screen-command - .key = f - - -[[ History menu ]] - -history-menu - .label = History - .accesskey = s -show-all-history-menuitem - .label = Show All History -show-all-history-command - .key = H -clear-recent-history-menuitem - .label = Clean Recent History… -history-synced-tabs-menuitem - .label = Synced Tabs -history-restore-last-session-menuitem - .label = Restore Previous Session -history-undo-menu - .label = Recently Closed Tabs -history-undo-window-menu - .label = Recently Closed Windows - - -[[ Bookmarks menu ]] - -bookmarks-menu - .label = Bookmarks - .accesskey = B -show-all-bookmarks-menuitem - .label = Show All Bookmarks -show-all-bookmarks-command - .key = b -// .key should not contain the letters A-F since the are reserved shortcut -// keys on Linux. -show-all-bookmarks-command-gtk - .key = o -bookmark-this-page-broadcaster - .label = Bookmark This Page -edit-this-page-broadcaster - .label = Edit This Page -bookmark-this-page-command - .key = d -subscribe-to-page-menuitem - .label = Subscribe to This Page… -subscribe-to-page-menupopup - .label = Subscribe to This Page… -add-cur-pages-menuitem - .label = Bookmark All Tabs… -recent-bookmarks-menuitem - .label = Recently Bookmarked - -other-bookmarks-menu - .label = Other Bookmarks -personalbar-menu - .label = Bookmarks Toolbar - .accesskey = B - - -[[ Tools menu ]] - -tools-menu - .label = Tools - .accesskey = T -downloads-menuitem - .label = Downloads - .accesskey = D -downloads-command - .key = j -downloads-command-unix - .key = y -addons-menuitem - .label = Add-ons - .accesskey = A -addons-command - .key = A - -sync-sign-in-menuitem - .label = Sign In To { sync-brand-short-name }… - .accesskey = Y -sync-sync-now-menuitem - .label = Sync Now - .accesskey = S -sync-re-auth-menuitem - .label = Reconnect to { sync-brand-short-name }… - .accesskey = R -sync-toolbar-button - .label = Sync - -web-developer-menu - .label = Web Developer - .accesskey = W - -page-source-broadcaster - .label = Page Source - .accesskey = o -page-source-command - .key = u -page-info-menuitem - .label = Page Info - .accesskey = I -page-info-command - .key = i -mirror-tab-menu - .label = Mirror Tab - .accesskey = m diff --git a/tools/migrate/examples/toolbar.ftl b/tools/migrate/examples/toolbar.ftl deleted file mode 100644 index 1d056553..00000000 --- a/tools/migrate/examples/toolbar.ftl +++ /dev/null @@ -1,24 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -urlbar-textbox - .placeholder = Search or enter address - .accesskey = d - - -[[ Toolbar items ]] - -view-bookmarks-broadcaster - .label = Bookmarks -view-bookmarks-command - .key = b -view-bookmarks-command-win - .key = i - -view-history-broadcaster - .label = History -view-history-command - .key = h -view-tabs-broadcaster - .label = Synced Tabs diff --git a/tools/migrate/migrate-l10n.py b/tools/migrate/migrate-l10n.py deleted file mode 100755 index 42eccf82..00000000 --- a/tools/migrate/migrate-l10n.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -# coding=utf8 - -import os -import sys -import json -import logging -import argparse -import importlib - -import hglib -from hglib.util import b - -from fluent.migrate.context import MergeContext -from fluent.migrate.errors import MigrationError -from fluent.migrate.changesets import convert_blame_to_changesets -from blame import Blame - - -def main(lang, reference_dir, localization_dir, migrations, dry_run): - """Run migrations and commit files with the result.""" - client = hglib.open(localization_dir) - - for migration in migrations: - - print('\nRunning migration {} for {}'.format( - migration.__name__, lang)) - - # For each migration create a new context. - ctx = MergeContext(lang, reference_dir, localization_dir) - - try: - # Add the migration spec. - migration.migrate(ctx) - except MigrationError: - print(' Skipping migration {} for {}'.format( - migration.__name__, lang)) - continue - - # Keep track of how many changesets we're committing. - index = 0 - - # Annotate legacy localization files used as sources by this migration - # to preserve attribution of translations. - files = ( - path for path in ctx.localization_resources.keys() - if not path.endswith('.ftl')) - blame = Blame(client).attribution(files) - changesets = convert_blame_to_changesets(blame) - known_legacy_translations = set() - - for changeset in changesets: - changes_in_changeset = changeset['changes'] - known_legacy_translations.update(changes_in_changeset) - # Run the migration for the changeset, with the set of - # this and all prior legacy translations. - snapshot = ctx.serialize_changeset( - changes_in_changeset, - known_legacy_translations - ) - - # Did it change any files? - if not snapshot: - continue - - # Write serialized FTL files to disk. - for path, content in snapshot.iteritems(): - fullpath = os.path.join(localization_dir, path) - print(' Writing to {}'.format(fullpath)) - if not dry_run: - fulldir = os.path.dirname(fullpath) - if not os.path.isdir(fulldir): - os.makedirs(fulldir) - with open(fullpath, 'w') as f: - f.write(content.encode('utf8')) - f.close() - - index += 1 - author = changeset['author'].encode('utf8') - message = migration.migrate.__doc__.format( - index=index, - author=author - ) - - print(' Committing changeset: {}'.format(message)) - if not dry_run: - try: - client.commit( - b(message), user=b(author), addremove=True - ) - except hglib.error.CommandError as err: - print(' WARNING: hg commit failed ({})'.format(err)) - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - description='Migrate translations to FTL.' - ) - parser.add_argument( - 'migrations', metavar='MIGRATION', type=str, nargs='+', - help='migrations to run (Python modules)' - ) - parser.add_argument( - '--lang', type=str, - help='target language code' - ) - parser.add_argument( - '--reference-dir', type=str, - help='directory with reference FTL files' - ) - parser.add_argument( - '--localization-dir', type=str, - help='directory for localization files' - ) - parser.add_argument( - '--dry-run', action='store_true', - help='do not write to disk nor commit any changes' - ) - parser.set_defaults(dry_run=False) - - logger = logging.getLogger('migrate') - logger.setLevel(logging.INFO) - - args = parser.parse_args() - - main( - lang=args.lang, - reference_dir=args.reference_dir, - localization_dir=args.localization_dir, - migrations=map(importlib.import_module, args.migrations), - dry_run=args.dry_run - ) diff --git a/tox.ini b/tox.ini index 78ebd64a..e50b967a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py27-cl, py35, py36 +envlist = py27, py35, py36 skipsdist=True [testenv] @@ -7,11 +7,3 @@ setenv = PYTHONPATH = {toxinidir} deps = six commands = python -m unittest discover -s tests/syntax - -[testenv:py27-cl] -deps = - six - compare-locales -commands = - python -m unittest discover -s tests/syntax - python -m unittest discover -s tests/migrate