blob: 2e328d589a0ce832631a45a98218c1c37f581410 [file] [log] [blame]
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/compiled_action.gni")
import("//build/fidl/fidl.gni")
import("//build/fidl/fidl_library.gni")
# Generates localized assets from source localized strings.
#
# Please check out `//src/intl/example/BUILD.gn` for example use of the target.
#
# Example instantiation:
#
# ```
# import("//build/intl/strings.gni")
# intl_strings("foo") {
# source = "strings.xml"
# source_locale = "en"
# output_locales = ["en", "fr", "es"]
# library = "fuchsia.intl.l10n"
# }
# ```
#
# Inputs:
#
# - Needs an input XML file (by convention named `strings.xml`), in the Android
# strings resource format to represent the source externalized strings.
#
# - Needs, for each supported language `lang`, an input XML file which contains
# translations of the messages contained in `strings.xml`. The source language
# is not special, so for example if your `strings.xml` contains English
# strings, you still need `strings_en.xml` or 'en/strings.xml'.
#
# Outputs:
#
# - An includable source file (language-dependent!) with generated constants
# that refer to all messages in the `strings.xml` file.
#
# - A set of files named "$target_gen_dir/lang/foo.json" for every `lang`,
# which maps the string IDs to messages in the appropriate language. Check out
# `//src/intl/example/BUILD.gn` for an example of how to bundle these files into
# a Fuchsia package.
#
# Parameters:
#
# library: (required string), a dot-separated library name to be
# used for the generated code. For example, in C++, the generated constants
# will be wrapped into a nested namespace `fuchsia::intl::l10n` in the
# example above.
#
# source: (required string), the source XML file containing
# Android-compatible externalized strings.
#
# source_locale: (optional string, default "en-US"), the source locale that
# the file specified under `source` is written in. This is used for
# bookkeeping only, the source locale is otherwise not special in any way.
#
# output_locales: (required list of strings), the list of locales for which
# to generate the localized assets. By convention, if the `source` is
# `strings.xml`, then a localized asset for language `foo` needs a source
# file named `strings_foo.xml`.
#
# same_dir_locales: (optional bool, defaults to false), if set to `true`, the
# locale files for the language `lang` are expected in the same directory as
# `strings.xml`, and named `strings_lang.xml`. If set to `false`
# (or left unset), the file names expected are `lang/strings.xml`.
#
template("intl_strings") {
# Best practices forward.
forward_variables_from(invoker,
[
"testonly",
"visibility",
"library",
"source",
"output_locales",
])
assert(defined(library), "Parameter library=... is required")
assert(defined(source), "Parameter source=... is required")
source_locale = "en-US"
if (defined(invoker.source_locale)) {
source_locale = invoker.source_locale
}
same_dir_locales = false
if (defined(invoker.same_dir_locales)) {
same_dir_locales = invoker.same_dir_locales
}
assert(defined(output_locales), "Parameter output_locales=[...] is required")
base_name = invoker.target_name
target_name = invoker.target_name
base_source = get_path_info(source, "name")
# Every target we generate in this template needs to be added here, so it
# could become a dependency of the final generated group target.
group_deps = []
# Generate a JSON file for each locale. Collect all files into a group.
manifest_resources = []
locale_resources = []
foreach(locale, output_locales) {
target_strings_file = "${locale}/${base_source}.xml"
if (same_dir_locales) {
target_strings_file = "${base_source}_${locale}.xml"
}
output_file_name = "${target_gen_dir}/${locale}/${base_name}.json"
locale_resources += [
{
foo = rebase_path(output_file_name, root_build_dir)
dest = "assets/locales/${locale}/${base_name}.json"
path = rebase_path(output_file_name, root_build_dir)
},
]
# TODO(fmil): This is an experiment with manifest file.
manifest_source_path = rebase_path(output_file_name, root_build_dir)
manifest_target_path = "assets/locales/${locale}/${base_name}.json"
manifest_resources += [ "${manifest_target_path}=${manifest_source_path}" ]
compiled_action_name = "${base_name}_to_json_${locale}"
group_deps += [ ":${compiled_action_name}" ]
compiled_action(compiled_action_name) {
tool = "//src/intl/strings_to_json:strings_to_json_bin"
tool_output_name = "strings_to_json"
sources = [
source,
target_strings_file,
]
outputs = [ output_file_name ]
args = [
"--replace-missing-with-warning",
"--source-locale",
source_locale,
"--source-strings-file",
rebase_path(source, root_build_dir),
"--target-locale",
locale,
"--target-strings-file",
rebase_path(target_strings_file, root_build_dir),
"--output",
rebase_path(output_file_name, root_build_dir),
]
}
} # for_each
strings_to_fidl_name = "${target_name}_fidl"
generated_fidl_file_name = "${target_gen_dir}/${base_source}.fidl"
manifest_file = "${target_gen_dir}/${base_name}.manifest"
write_file(manifest_file, manifest_resources)
group("${base_name}_l10n_assets_group") {
metadata = {
resources = locale_resources
manifest = manifest_resources
}
}
group_deps += [ ":${base_name}_l10n_assets" ]
generated_file("${base_name}_l10n_assets") {
deps = [ ":${base_name}_l10n_assets_group" ]
outputs = [ "${target_gen_dir}/${base_name}_l10n_assets.json" ]
data_keys = [ "resources" ]
output_conversion = "json"
}
if (current_toolchain == fidl_toolchain) {
# Generates a FIDL file with all the strings constants defined.
# It is only ran in the FIDL toolchain because we want to run this
# conversion only once.
compiled_action(strings_to_fidl_name) {
tool = "//src/intl/strings_to_fidl:strings_to_fidl_bin"
tool_output_name = "strings_to_fidl"
sources = [ source ]
outputs = [ generated_fidl_file_name ]
args = [
"--input",
rebase_path(source, root_build_dir),
"--output",
rebase_path(generated_fidl_file_name, root_build_dir),
"--library",
library,
]
} # compiled_action
# Generates the FIDL library based on the generated FIDL file from the
# above target. This invocation is special because it needs to depend
# on a non-fidl library. It must be a special invocation because all
# FIDL invocations in different toolchain assume that the dependencies
# have FIDL subtargets.
fidl(library) {
sources = [ generated_fidl_file_name ]
non_fidl_deps = [ ":${strings_to_fidl_name}" ]
# Since we use FIDL as intermediate representation and nobody will read
# it, we don't need to lint.
should_lint = false
}
} else {
# The non-FIDL toolchain FIDL libraries are built normally; except based
# off of the generated FIDL file.
fidl(library) {
sources = [ generated_fidl_file_name ]
}
}
# This lists the resources without the FIDL library.
resource_deps = group_deps
# This group target has the same name as the template invoker, and contains
# all generated targets as its deps, so that all the deps are executed when
# the template is expanded.
group_deps += [ ":${strings_to_fidl_name}($fidl_toolchain)" ]
group(target_name) {
public_deps = group_deps
metadata = {
# Used by distribution_manifest() template. Ensure that the resources,
# but not the library is installed in a package that depends on this target.
distribution_entries_barrier = resource_deps
}
}
}