{"docs": [{"text": "A declarative, file-based static website generator New Grow 1.0 for Python 3 has been released! Read migration notes arrow_forward Grow.dev is a static site generator optimized for building highly-interactive, localized microsites. Grow.dev focuses on providing optimal workflows and developer ergonomics for creating projects that are highly maintainable in the long-term. Grow.dev encourages a strong-but-simple separation of content and presentation, and makes maintaining content in different locales and environments a snap. Key features YAML-based content management with locale and environment variations Custom YAML types representing documents, data files, strings, etc. Jinja templates Localization inbuilt (for content, translations, and URLs) Build sharding for massive websites Extensions and integrations with content sources No opinion about the client-side frontend stack Install Read installation instructions Clone and run our starter project on GitHub Learn Grow.dev prefers configuration over code for defining a web site's content and architecture. We keep Grow.dev simple so that you can learn about all its capabilities within an hour or less. Try the codelab arrow_forward", "location": "/", "title": "Introduction"}, {"text": "Install Grow.dev Grow.dev is a Python 3 program. We recommend using Pipenv to manage Python installations and versions across projects. To use Pipenv with Grow.dev, see the below steps. Using Pipenv permits you to have a different version of Python and a different version of Grow.dev installed on a per-project basis. Install Pipenv Mac setup Install Homebrew. Install Pipenv and LibYAML: brew install pipenv libyaml Linux setup Install (Pipenv)[https://pypi.org/project/pipenv/]. Create a Pipfile Pipenv uses Pipfile files to specify Python installations and dependencies. Run the following to add a Pipfile and Pipfile.lock: # Setup the pipenv config using Python 3 pipenv --python 3 # Install the grow dependency. pipenv install grow~=1.0.0 Need to use a different version of Grow.dev? Update the versions of grow and python_version in Pipfile accordingly. Node setup Most Grow.dev projects rely on Node in some way for JavaScript extensions. We recommend using nvm for managing Node versions. Read nvm install instructions Most Grow.dev extensions rely on Node versions 10.x or higher. Note for Mac users: many Node programs (i.e. popular node-sass) may require Xcode and its command line tools to compile. Install Xcode using the Mac App Store, and then follow the xcode-select install instructions. Alias For convenience, we recommend adding a global alias for grow to pipenv run grow. This permits you to run grow instead of pipenv run grow for all Grow commands. # In .bash_profile (or similar). alias grow='pipenv run grow' Using a starter We recommend using a starter project to get started with your first Grow.dev website. Get started with our base starter which provides a Pipfile and a project structure that's ready to go. Next steps Once the above steps are completed, you can invoke grow to use the CLI. Run the below commands from within your project directory: # Output help. grow --help # Install project dependencies (Python and Node extensions). grow install # Run the development server. grow run # Build the project. grow build Once you're familiar with the overall setup, most projects can be started with: pipenv install grow install grow run Troubleshooting LibYAML If you are seeing this message: Warning: libyaml missing, using slower yaml parser. when running grow you may not have LibYAML installed or need to run a command to fix Pipenv to correctly use it. Learn about the LibYAML fix. watchdog on macOS and Python 3.8 Certain configurations of macOS and xCode may run into issues installing the watchdog dependency. The simplest way to resolve this is to use Python 3.7, which isn't impacted by the issue. Many systems will have Python 3.7 available, but newer systems may only have Python 3.8. # Install Python 3.7.9 globally. brew install pyenv pyenv install 3.7.9 pyenv global 3.7.9 # Run from your Grow project directory. pipenv --rm pipenv install Getting Python 3x on macOS We recommend using the newest verson of macOS which has the newest versions of Python 3 available. If you are on an older version of macOS, you can use pyenv to install Python 3: brew install pyenv pyenv install 3.7.9 pyenv global 3.7.9", "location": "/install/", "title": "Install"}, {"text": "Installing extensions Grow has a powerful and simple extension system that enables you to extend the functionality of Grow with extensions. Installing extensions Grow supports an extensions.txt file as part of the pod. When the file is present the grow install command will handle the installation of the extensions. # extensions.txt git+git://github.com/grow/grow-ext-contentful The extensions.txt follows the same format as a normal pip requirements.txt style. This means you can install pip packages or directly from version control. See the documentation for each extension for instructions on how to properly configure the extension and what settings to add to the podspec.yaml file. Finding extensions Extensions can be found by searching for grow-ext- in pypi or github. Custom extensions When possible, extensions should be created as separate repositories and use the extensions.txt file to reference the extension. This helps the extensions be reusable across projects. Repositories for grow extensions should be named using the grow-ext- format. For example: grow-ext-budou, grow-ext-google-forms, grow-ext-contentful. In some cases it makes more sense to write the extension inside the same repository as it is very specific to the site. The same principles apply just put the extension files into a subdirectory inside the extensions/ directory. Extensions are standard Python modules, so your site's extensions folder must be set up appropriately, with __init__.py files: \u251c\u2500\u2500 /extensions # All your extensions | \u251c\u2500\u2500 /__init__.py # Empty file, required by Python | \u2514\u2500\u2500 /extension_name # Subfolder for custom extension | \u251c\u2500\u2500 /__init__.py # Empty file, required by Python | \u251c\u2500\u2500 /extension_name.py # Extension code", "location": "/extensions/install/", "title": "Install extensions"}, {"text": "Legacy extensions The following deals with developing legacy Grow extensions. For developing using the new extension format see the new extension docs. Jinja2 extensions Sites can directly extend Grow's Jinja2 rendering environment by including custom Jinja2 extensions. Jinja2 extensions can add site-specific filters, tests, globals, and extend the template parser. See Jinja2's documentation on extensions. Specify additional, site-specific Jinja2 extensions in podspec.yaml: # podspec.yaml extensions: jinja2: - extensions.triplicate.triplicate.Triplicate Define the extension in a corresponding place in the /extensions/ folder. # /extensions/triplicate/triplicate.py from jinja2.ext import Extension def do_triplicate(value): return value * 3 class Triplicate(Extension): def __init__(self, environment): super(Triplicate, self).__init__(environment) environment.filters['triplicate'] = do_triplicate Now you can use your custom triplicate filter in your Jinja2 templates. # /views/base.html {{10|triplicate}}", "location": "/extensions/legacy/", "title": "Legacy extensions"}, {"text": "Create extensions Grow has a powerful extension system that enables you to extend the functionality of Grow with extensions. Example extension As an example of a simple Grow extension see the html min extension. Anatomy of an extension Grow extensions work by creating hooks to bind to events that happen within Grow. For example, a hook to change the contents of a page after it has already been rendered. Each extension can bind to any number of hooks. Extensions are provided with a configuration optionally defined in the podspec.yaml that can be used to control the extension's functionality: # podspec.yaml ext: - extensions.html_min.HtmlMinExtension: options: remove_comments: true reduce_boolean_attributes: false For complex extensions specific hooks can be enabled or disabled piecemeal: # podspec.yaml ext: - extensions.complex.ComplexExtension: enabled: - post_render disabled: - dev_file_change Extension hooks Base hooks are defined by Grow and can be extended in the extension. When hooks are triggered in Grow (ex: after the content is rendered) it calls the trigger method on the hook. Hook triggers follow some basic conventions: The first argument is the previous_result from any hooks already triggered. Arguments change depending on the hook and are documented below. Each trigger method should have *_args, **_kwargs as the last two arguments. For hooks that are expecting a specific result a result object will be provided in the previous_result argument and should just be updated as needed. If there is a specific return type it will be documented with the hook. Even if your extension doesn't change the previous_result, the previous_result should be returned to continue the chain of extensions. By using the *_args, **_kwargs on all trigger methods it allows Grow to add additional arguments to the hook without breaking existing extensions. from grow.extensions import hooks class MyPostRenderHook(hooks.PostRenderHook): \"\"\"Handle the post-render hook.\"\"\" def trigger(self, previous_result, doc, raw_content, *_args, **_kwargs): \"\"\"Execute post-render modification.\"\"\" content = previous_result if previous_result else raw_content # Do something to modify the contents. return content Extensions A simple extension only needs to extend the BaseExtension and define the available_hooks property. from grow import extensions class MyExtension(extensions.BaseExtension): \"\"\"Example Extension.\"\"\" @property def available_hooks(self): \"\"\"Returns the available hook classes.\"\"\" return [MyPostRenderHook] For special cases when you need to have additional arguments to the hook class you can create hook getters in the extension to control how the hook is created. from grow import extensions class MyExtension(extensions.BaseExtension): \"\"\"Example Extension.\"\"\" @property def available_hooks(self): \"\"\"Returns the available hook classes.\"\"\" return [MyPostRenderHook] def post_render_hook(self): \"\"\"Returns the hook object.\"\"\" return MyPostRenderHook(self, other_arg=True) Grow Hooks The following hooks are currently available for extensions. hooks.DevFileChangeHook When a file is changed when running the development server this hook is triggered. def trigger(self, previous_result, pod_path, *_args, **_kwargs): return previous_result pod_path \u2013 path of the file that changed in the pod. See the core routes extension for an example of the dev file change. hooks.DevHandlerHook When running the local development server the dev handler hook allows for adding custom handlers for the development server. def trigger(self, previous_result, routes, *_args, **_kwargs): return previous_result routes \u2013 The routes object for adding the handler. See the core routes extension for an example of the dev handler. hooks.PostRenderHook def trigger(self, previous_result, doc, raw_content, *_args, **_kwargs): return previous_result doc \u2013 The document being rendered. This can be a normal document or a static document. raw_content \u2013 The raw rendered content. See the html min extension for an example of the dev handler. hooks.PreprocessHook def trigger(self, previous_result, config, names, tags, run_all, rate_limit, *_args, **_kwargs): return previous_result config \u2013 Configuration for the preprocessor from the podspec. names \u2013 Names of the preprocessors being run. tags \u2013 Tags of the preprocessors being run. run_all - If all preprocessors are being run. rate_limit - Time in seconds when rate limiting should be used between bulk processing. hooks.PreRenderHook def trigger(self, previous_result, doc, original_body, *_args, **_kwargs): return previous_result doc \u2013 The document being rendered. This can be a normal document or a static document. original_body \u2013 The original content before being rendered.", "location": "/extensions/create/", "title": "Create extensions"}, {"text": "Legacy preprocessors Sites can define custom preprocessors to do pretty much anything at build time and run time. Custom preprocessors can leverage all of the builtin preprocessor controls, such as the grow preprocess command, the --preprocess flag, and options like name, autorun, and tags. Specify and use your custom preprocessor in podspec.yaml: # podspec.yaml extensions: preprocessors: - ext.hello.HelloPreprocessor preprocessors: - kind: hello person: Zoey Define the preprocessor in the /ext/ folder. Grow preprocessors should subclass grow.Preprocessor and use ProtoRPC Messages to define their configuration. # /ext/hello.py import grow from protorpc import messages class HelloPreprocessor(grow.Preprocessor): \"\"\"Says hello to a person.\"\"\" KIND = 'hello' class Config(messages.Message): person = messages.StringField(1) def run(self, build=True): print 'Hello, {}!'.format(self.config.person) Lastly, in the same /ext folder, create an empty file called __init__.py to let Grow know that this is a module. Now, you can use the preprocessor. $ grow preprocess Hello, Zoey!", "location": "/extensions/preprocessor-legacy/", "title": "Legacy preprocessors"}, {"text": "Directory structure Grow sites are encapsulated into directories that follow a specific structure. These directories are called \"pods\". Grow uses the configuration files and the structure of files in each pod to declaratively build your site. Pods contain source files, but for deployment, Grow builds only what's needed to serve your site. Sources and other \"internal\" files are never built to the output directory. Example structure Items marked with * are inbuilt, and their names cannot change. Other items aren't required by Grow, but are often found by convention. \u251c\u2500\u2500 /build # Default location for builds. \u251c\u2500\u2500 /content* # All your content. | \u251c\u2500\u2500 /pages # A content collection. | \u251c\u2500\u2500 /_blueprint.yaml* # A blueprint. | \u251c\u2500\u2500 /about.md # A content document. | \u251c\u2500\u2500 /contact.md | \u2514\u2500\u2500 /index.md | \u2514\u2500\u2500 /posts | \u251c\u2500\u2500 /_blueprint.yaml* | \u251c\u2500\u2500 /my-first-post.md | \u2514\u2500\u2500 /hello-grow.md \u251c\u2500\u2500 /dist # Compiled files like minified js and css. | \u251c\u2500\u2500 /css # Used for static serving of minified files. | \u2514\u2500\u2500 /composite | \u251c\u2500\u2500 global.min.css | \u2514\u2500\u2500 main.min.css | \u2514\u2500\u2500 /js | \u2514\u2500\u2500 /composite | \u251c\u2500\u2500 global.min.js | \u2514\u2500\u2500 main.min.js \u251c\u2500\u2500 /source # Frontend source files. | \u251c\u2500\u2500 /js | \u2514\u2500\u2500 /composite | \u251c\u2500\u2500 /global.js | \u2514\u2500\u2500 /main.js | \u251c\u2500\u2500 /sass | \u2514\u2500\u2500 /composite | \u251c\u2500\u2500 /global.sass | \u2514\u2500\u2500 /main.sass | \u2514\u2500\u2500 /static # Static files. | \u2514\u2500\u2500 /images | \u2514\u2500\u2500 /favicon.png \u251c\u2500\u2500 /translations* # All your translation data. | \u251c\u2500\u2500 /messages.pot # Message catalog template. | \u2514\u2500\u2500 /de | \u2514\u2500\u2500 /messages.po # A message catalog. | \u2514\u2500\u2500 /fr | \u2514\u2500\u2500 /messages.po | \u2514\u2500\u2500 /it | \u2514\u2500\u2500 /messages.po \u251c\u2500\u2500 /views* # Jinja templates. \u251c\u2500\u2500 /partials* # Partial templates. | \u2514\u2500\u2500 /hero | \u251c\u2500\u2500 /hero.html | \u251c\u2500\u2500 /hero.js | \u2514\u2500\u2500 /hero.sass | \u2514\u2500\u2500 /base.html # Base template for rendering partials. | \u2514\u2500\u2500 /pages.html | \u2514\u2500\u2500 /posts.html \u251c\u2500\u2500 /package.json # JS dependencies. \u2514\u2500\u2500 /podspec.yaml* # Pod specification.", "location": "/reference/directory-structure/", "title": "Directory structure"}, {"text": "Podspec Grow pods must contain a file named podspec.yaml. The podspec contains flags and a few definitions that specify various behavior and properties of your site, such as URLs, the version of Grow compatible with the pod, and localization information. podspec.yaml title: Project title. description: Project description. home: /content/pages/.yaml static_dirs: - static_dir: /static/ serve_at: /site/files/ localization: root_path: /{locale}/ default_locale: en locales: - de - en - fr - it aliases: en_uk: en_GB import_as: en_uk: - en_GB require_translations: false require_translations@env.prod: true preprocessors: - kind: sass sass_dir: /source/sass/ out_dir: /static/css/ meta: key: value sitemap: enabled: yes path: /sitemap.xml collections: - pages locales: - en - fr deployments: default: destination: local out_dir: grow-codelab-build/ env: name: prod host: example.com port: 80 scheme: https static_dirs A list of directories in the pod to treat as servable static files. Unlike the static_dir shorthand flag, this config provides additional customization and control over the source directory and the path at which the files are served. static_dirs: # Equivalent to the \"static_dir\" shorthand flag. - static_dir: /static/ serve_at: /static/ # Serves files in the /static/ directory of the pod at the URL path /files/. - static_dir: /static/ serve_at: /files/ # Serves files in the /static/ directory of the pod at the root. - static_dir: /static/ serve_at: / If you do not wish to use Grow's content management or templating features, you can leverage the other features of the system (such as testing, building, and deployment) by simply creating a podspec.yaml file and following the last above example. This can be a good way to migrate an existing site into Grow and slowly add new site sections leveraging Grow's content and templating features. Fingerprints Grow can rewrite static file paths with fingerprints. static_dirs: - static_dir: /source/ serve_at: /static/ fingerprinted: true In the above example, a file at /source/images/file.png would be served at /static/images/file-.png where is an md5 hash of the file's contents. Filtering By default grow ignores building any static files that start with a .. The behavior can be changed by adding a main level filter or selectively by adding the filter to a static_dirs item. filter: ignore_paths: - \\.DS_STORE include_paths: - \\.htaccess The ignore_paths defines regex patterns for which files to ignore. The include_paths defines regex patterns that override the ignore patterns. So if you want to ignore all files that start with a . except for .htaccess files you could do a filter like this (since the default is to ignore dot files you don't need a ignore_paths): filter: include_paths: - \\.htaccess localization The default localization configuration for all content in the pod. default_locale Sets the global, default locale to use for content when a locale is not explicitly. This allows you to set a global, default locale for the content throughout your site. For example, if you wanted to serve English content at http://example.com/site/ and localized content at http://example.com/{locale}/site/, you would set default_locale to en. It also allows you to use a non-English language as the source language for content (for example, when translating from Chinese to English). default_locale: en locales A list of locale identifiers that your site is available in. Language codes will be derived from the identifiers in this list and individual translation catalogs will be created for each language. The {locale} converter can be used in path configs (such as in podspec.yaml or in a blueprint). localization: locales: - en_US - de_DE - it_IT aliases A mapping of aliases to locale identifiers. This can be used to translate a Grow locale to a locale used by your web server, should the identifiers differ. localization: aliases: en_uk: en_gb import_as A mapping of external to internal locales, used when translations are imported. When translations are imported using grow translations import, Grow converts external locales to internal locales. This mapping can be useful if you are working with a translation provider that uses non-standard locales. localization: import_as: en_uk: - en_GB require_translations Flag for determining if the build requires all strings in use to be translated before being successful. To target a specific deployment use the @env. format. localization: require_translations: false require_translations@env.prod: true groups Categorize groups of locales together to allow for easy reference when tagging strings. # podspec.yaml localization: groups: group1: - de - fr - it # /content/collectiion/document.yaml foo: base foo@locale.group1: tagged for de, fr, or it locales. If there are already locales being used: # /content/collectiion/document.yaml foo: base foo@(en_US|en_UK): normal localization usage. foo@locale.group1: tagged for de, fr, or it locales. preprocessors A list of preprocessors. The type of preprocessor is determined by the kind key. The remaining keys are configuration parameters for the preprocessor. meta Metadata set at a level global to the pod. Metadata here is arbitrary, unstructured, and can be used by templates via {{podspec.meta}}. Typcal uses for metadata may be for setting analytics tracking IDs, site verification IDs, etc. meta: key: value google_analytics: UA-12345 sitemap Add sitemap to autogenerate a sitemap.xml file for your project. sitemap: enabled: yes path: \"/{root}/sitemap.xml\" # Optional. collections: # Optional. - pages locales: # Optional. - en - fr deployments A mapping of named deployments. The deployment destination is determined by the destination key. The remaining keys are configuration parameters for the deployment. The default name can be used to specify the pod's default deployment. An env can optionally be specified. default: destination: gcs bucket: staging.example.com production: destination: gcs bucket: example.com You can also specify the environment on a per-deployment basis. The environment properties are used in the {{env}} object, as well as used to derive the host, port, and scheme for the url properties of documents and static files. These are also used in sitemap generation. deployments: example: destination: local keep_control_dir: no control_dir: ./private/my-project/ out_dir: ./www/html/ env: host: example.com scheme: https port: 9000 footnotes Add footnotes to configure how footnotes are generated in documents. footnotes: numeric_locales_pattern: US$ symbols: - \u221e - \u25cf - \u25d0 - \u25d5 The default set of symbols follows the Chicago Manual footnote style. Symbols are repeated after the initial list is exhausted. For example, the above configuration would make the fifth footnote use \u221e\u221e as the symbol. By default, the DE and CA territories use numeric symbols instead of normal symbols. The numeric_locales_pattern configures what regex to apply to the locales to determine if it should use the numeric symbols instead of the normal symbol set. Ex: numeric_locales_pattern: (US|CA)$ would make all the US and CA territories use the numeric symbols. You can force all locales to use numeric symbols by using use_numeric_symbols: True or turn off the usage of numeric symbols by using use_numeric_symbols: False.", "location": "/reference/podspec/", "title": "Podspec"}, {"text": "Templates Grow templates are stored in a pod's /views/ directory. Templates are processed using the Jinja2 template language. Grow extends Jinja2 with a few variables and functions that make building content-rich web sites more convenient. Variables have no prefix and are part of the global template scope. Functions are prefixed into the g namespace, for example: g.. Variables There are several built-in global variables available to templates. Because these variables are not namespaced, take caution not to overwrite their values. doc The current content document associated with the current page that's being rendered. See the full documentation for the document API. {{doc.category}} # Document's category {{doc.title}} # Document's canonical title. {{doc.titles('nav')}} # Document's \"nav\" title. {{doc.html|safe}} # Document's rendered Markdown body. {{doc.foo}} # Value of the \"foo\" custom field from the YAML front matter. {{doc.collection}} # Document's Collection. {{doc.collection.foo}} # Value of the \"foo\" custom field from the collection's `_blueprint.yaml`. env The rendering environment that exists when the page is being built or served. {{env.host}} {{env.name}} {{env.port}} {{env.scheme}} {{env.fingerprint}} podspec Refers to the podspec.yaml configuration file and allows you to access pod-wide settings in templates. {{podspec.title}} # Pod's title. {{podspec.project_id}} # Pod's project ID. Functions _ _() The _ tag is a special function used to tag strings in templates for both translation and message extraction. # Simple translation. {{_('Hello')}} # A translation with a placeholder. {{_('Hello, {name}', name='Alice')}} g.categories g.categories() Lists content documents within a collection and groups them by their $category. Useful for generating navigation and categorized lists of documents. {% for category, docs in g.categories('pages') %}

{{category}}

    {% for doc in docs %}
  • {{doc.title()}} {% endfor %}
{% endfor %} g.collection g.collection() Returns a Collection object, given a collection path. g.collections g.collections() Returns a list of all Collection objects in the pod, or lists Collection objects given a list of collection paths. {{g.collections()}} {{g.collections(['pages'])}} g.csv g.csv(, locale=) Parses a CSV file and returns a list of dictionaries mapping header rows to values for each row. Optionally use keyword arguments to filter results. This can be particularly useful for using a spreadsheet for localization (where rows represent values for different locales). {% set people = g.csv('/data/people.csv') %} {% for person in people %}
  • {{person.name}} {% endfor %} g.date g.date(, from=) Parses a string into a Date object. Uses Python date formatting directives. # Returns a DateTime given a string and a format. {{g.date('12/31/2000', from='%m/%d/%Y')}} g.doc g.doc(, locale=) Gets a single content document, given its pod path. {% set foo = g.doc('/content/pages/index.html') %} {{foo}} # Returns the fr version of a document. {{g.doc('/content/pages/index.html', locale='fr')}} g.docs g.docs(, order_by=, locale=) Searches content documents within a collection.
      {% for doc in g.docs('pages') %}
    • {{doc.title}} {% endfor %}
    The documents can also be sorted by multiple fields.
      {% for doc in g.docs('pages', order_by=('dates.published', 'title')) %}
    • {{doc.title}} {% endfor %}
    g.json g.json() Returns a loaded JSON object, given a JSON file's pod path. g.locales g.locales() Returns a list of Locale class given a list of locale identifiers. g.nav Not implemented Returns an object which can be used to create navigation. g.static g.static() Returns a StaticFile object corresponding to a static file contained within the pod. is the full pod path of the static file. You can access the path property of StaticFile.url to retrieve an absolute link to the file's serving path. It is a best practice to always refer to static files using the g.static tag rather than referring to their URLs directly. This has the benefit of making URL changes easy and Grow will catch broken links to static files at build time. Prior to using g.static, routes must be configured in the static_dirs property of podspec.yaml. g.static supports static file localization by way of the localization option of the static_dirs setting in podspec.yaml. If a localized static file exists, it will return the object corresponding to the localized static file. If it doesn't, it will return the object corresponding to the base static file. # Uses the current document's locale. {{g.static('/static/example.png', locale=doc.locale)}} # Uses a hardcoded locale. {{g.static('/static/example.png', locale='de')}} g.statics g.statics() Returns a list of StaticFile objects from in a directory within your pod. {% for static_file in g.statics('/source/images/') %} {% endfor %} g.url g.url() Returns the URL object for a document, given a document's pod path. Access the path property of the URL object to retrieve an absolute link to the document. Home g.yaml g.yaml() Returns a parsed yaml object, given a yaml file's pod path. Respects translation tagging. Filters currency Formats currency in a localized format. Use's Babel's format_currency. {{12345|currency('USD')}} date Formats localized and non-localized dates. Use's Babel's format_date. {{date_object|date(format='short')}} {{date_object|date(format='short', locale='ja_JP')}} {{date_object|date(format=\"yyyy.MM.dd G 'at' HH:mm:ss zzz\")}} datetime Formats localized and non-localized datetimes. Use's Babel's format_datetime. decimal Formats decimal in a localized format. Use's Babel's format_decimal. {{123.45|decimal()}} deeptrans Recursively applies the gettext translation function to strings within a dictionary. {% set content = { 'key': 'String', 'item_list': [ 'String 1', 'String 2' ] } %} {{content|deeptrans}} jsonify Converts a dictionary into JSON. {{dict_object|jsonify}} markdown Renders Markdown content into HTML. Use in conjunction with the safe filter to render HTML to a page. {{markdown_content|markdown}} {{markdown_content|markdown|safe}} number Formats numbers in a localized format. Use's Babel's format_number. {{1234.567|number}} percent Formats percentages in a localized format. Use's Babel's format_percent. {{0.123|percent}} relative Generates a relative URL (from the perspective of the current document context) from an absolute URL path. {{g.doc('/content/pages/home.yaml').url|relative}} shuffle Randomizes the order of items in a list. {{[1,2,3,4,5]|shuffle}} slug Creates a slug from text. {{'Hello World'|slug}} time Formats localized and non-localized times. Use's Babel's format_time.", "location": "/reference/templates/", "title": "Templates"}, {"text": "Collections All content in Grow is stored as flat files in your pod's /content/ directory. Content is grouped into collections, and each collection contains a single blueprint and many documents. Blueprints describe the structure of all documents in the collection. Grow makes it easy to separate content from presentation, but ultimately leaves the choice up to you. Content documents can be associated with URLs and with views (so they represent pages in your site), or not. Content documents without URLs are simply used internally, and can be referenced by other content documents. Blueprints Every content collection must have a blueprint. Blueprints define how content is structured, displayed, and served. Blueprints are stored as YAML files in your pod's content directory. For example, a blueprint for a collection \"people\" would be /content/people/_blueprint.yaml path: /people/{slug}/ # The URL path format for content. view: /views/people.html # The template to use. localization: # Overrides localization from podspec.yaml. path: /{locale}/people/{slug}/ locales: - de - fr - it path Specifies the URL path format for all content in this collection. Documents inherit the path specified in the blueprint. If path is omitted, content in this collection will not be generated into pages, unless a document specifies its own $path. If path is specified, view is a required field. See a list of path formatters.url.path}}#content-document-path-formatters). $path: /{root}/{base}/ view Specifies which template should be used to render content in this collection. If view is specified, path is a required field. # Documents in this collection will use the following template. $view: /views/pages.html localization Localization configuration for content in this collection. path Specifies a URL path format for localized content. By specifying both path and localization:path, you can use different formats for the URL paths for \"root\" and localized content. $localization: path: /{locale}/people/{slug}/ locales Specifies a list of locales that documents in this collection are available in. Each document's path will be expanded using locales to derive the URLs that the document is available at. $localization: locales: - de - fr - it categories The categories key contains a list of categories that documents inside the collection can fall into. A collection's categories can be used in conjunction with the g.categories template function to iterate over the documents in the collection, grouped by category.", "location": "/reference/collections/", "title": "Collections"}, {"text": "Documents All content in Grow is stored inside content documents. Content documents are Markdown and YAML files in a pod's /content/ directory. Documents optionally have a path property which allows the document to be exposed as a page in your site. If a document does not have a path, it is considered to be a partial document and can be included and re-used by other documents. Anatomy File types Aside from the _blueprint.yaml file, files in a content collection's directory are treated as content documents. Grow accepts content documents in the following formats, indicated by their file extensions: HTML (.html, .htm) Markdown (.markdown, .md, .mdown, .mkdn, .mkd) YAML (.yaml, .yml) Document path The document path of a content document is its path relative to the pod's /content/ directory. For example, a document whose pod path is /content/pages/welcome.md would have a document path of pages/welcome.md. Front matter YAML front matter is YAML metadata that is prepended to a document's body. Front matter contains fields. Field names prefixed with a dollar sign ($) are ones which are built-in to Grow. Front matter is encapsulated by three dashes (---). From views, fields can be accessed using doc. where is the name of the field. The dollar sign prefix should be omitted from field names accessed using template variables. As long as a blueprint specifies a document's view and its path, including YAML front matter in a content document is optional. Constructors Yaml constructors can be used to load in other documents or files into fields of the document. csv: !g.csv /pod/path/to.csv doc: !g.doc /content/page/about.yaml json: !g.json /pod/path/to.json static: !g.static /pod/path/to.img string: !g.string string.key.reference url: !g.url /content/page/about.yaml yaml: !g.yaml /pod/path/to.yaml Deep reference Yaml and JSON constructors can also reference specific keys in the referenced yaml file. yaml: !g.yaml /pod/path/to.yaml?key.sub_key json: !g.json /pod/path/to.json?key.sub_key String reference The !g.string is a special constructor that makes it easy to reference strings defined in an yaml file. This makes it easier to reuse strings in multiple places or have the strings managed in a third party process (such as a Google Sheet). All strings referenced by the !g.string constructor are defined in yaml files in the /content/strings/ directory. The value of the constructor is in the format of .. As an example: # /content/strings/products.yaml categories: art: Art tech: Technology science: Science # /content/page/art.yaml category: title: !g.string products.categories.art Body A document's body is the stuff that comes after its YAML front matter. For Markdown-formatted documents, Grow provides a shortcut for accessing rendered HTML using {{doc.html}} (see the html API function below). The unprocessed body contents can be accessed with {{doc.body}}. Rendering and serving Content documents are servable if they have a path (the URL path the document should be served at) and a view (the template used to render the document). By default, path and view are inherited from the collection's blueprint. If the blueprint does not have a path and a view set, you may specify $path and $view at the document-level. This also means that you can override the $path and $view on a document-by-document basis. $path: /about/ # Serves this document at /about/. $view: /views/base.html # Renders this document with /views/base.html. Example documents Markdown body Markdown-formatted documents can have optional YAML front matter, which is delimited using ---. # /content/pages/foo.md \u200b--- $title: Hello, Grow! $category: Get started \u200b--- # Welcome to Grow! This is a [Markdown](http://daringfireball.net/projects/markdown/) document. - I can use... - ... Markdown syntax... - ... to write my content. YAML body YAML-formatted documents never use a separate YAML front matter. {{doc.html}} and {{doc.body}} are both None for YAML-formatted content documents. # /content/pages/bar.yaml $title: Hello, Grow! $category: Get started key1: value1 key2: value2 HTML body HTML-formatted documents have YAML front matter and an HTML body. As you'd expect, {{doc.html}} yields the HTML source for this document, and you'd likely want to use this as {{doc.html|render|safe}} in order to render the HTML within the tag's context. HTML-formatted documents are particularly useful when a content document has its own, unique presentation, that's closely coupled to its content structure. For example, if your collection has an index page, and if the index page has its own unique presentation that is never used anywhere else on the site, the index content document could define its own HTML template unique to itself. # /content/pages/index.html \u200b--- $title: Hello, Grow! $category: Get started sections: - title: Section 1 text: Lorem ipsum dolor sit amet. - title: Section 2 text: Lorem ipsum dolor sit amet. - title: Section 3 text: Lorem ipsum dolor sit amet. \u200b--- {% for section in doc.sections %}

    {{section.title}}

    {{section.text}} {% endfor %} Functions There are several API functions available for documents. These are implemented as functions rather than properties because they accept optional parameters. next next() Returns the next document from a list of documents. If no list is provided, the default document ordering within a collection is used. If there is no next document, None is returned. # Returns the next document from the default list of documents. {{doc.next()}} # # Returns the next document from a custom list of documents. {% set doc1 = g.doc('/content/pages/foo.md') %} {% set doc2 = g.doc('/content/pages/bar.md') %} {{doc.next([doc1, doc, doc2])}} # prev prev() Opposite of next. Returns the previous document from a list of documents. If no list is provided, the default document ordering within a collection is used. If there is no previous document, None is returned. # Returns the previous document from the default list of documents. {{doc.prev()}} # # Returns the previous document from a custom list of documents. {% set doc1 = g.doc('/content/pages/foo.md') %} {% set doc2 = g.doc('/content/pages/bar.md') %} {{doc.prev([doc1, doc, doc2])}} # titles A function that returns a title, given a title name. Allows for cascading titles. Useful for giving the document a different title in different contexts (for example, a breadcrumb or a side menu). If the parameter is omitted or None, the document's canonical title is used. $title: Example Hello World Document $titles: nav: Hello World breadcrumb: Hello World Document {{doc.titles('nav')}} # Hello {{doc.titles('breadcrumb')}} # Hello World Document {{doc.titles('unknown')}} # Example Hello World Document {{doc.title()}} # Example Hello World Document Properties Documents have a few built-in properties that cannot be overwritten by configs. base The basename (minus extension) of the document's file. # In document /content/pages/foo.md {{doc.base}} # foo body The unprocessed body of the document. collection A reference to the document's collection. # In document /content/pages/foo.md {{doc.collection}} # collection_base A reference to the collection's relative base directory. # In document /content/pages/foo.md {{doc.collection_base}} # / # In document /content/pages/sub/foo.md {{doc.collection_base}} # /sub/ collection_path A reference to the document's path relative collection directory. # In document /content/pages/foo.md {{doc.collection_path}} # /foo.md # In document /content/pages/sub/foo.md {{doc.collection_path}} # /sub/foo.md exists Whether a document exists. {% set page = g.doc('/content/pages/home.yaml') %} {{page.exists}} footnotes Manages footnotes in a document and displays corresponding symbols. This needs to be considered.{{doc.footnotes.add('More details available.')}} Can also make links to the list of footnotes. {% set symbol = doc.footnotes.add('More details available.') %} This needs to be considered.{{symbol}} Footnotes can be displayed later on the page. {% for symbol, value in doc.footnotes %}

    {{symbol}} : {{_(value)}}

    {% endfor %} The footnotes can be configured using the $footnotes field in the document or inherits the podspec footnotes configuration. html Returns the document's body (for .md documents, the Markdown body) rendered as HTML. {{doc.html|safe}} # Avoid escaping the HTML by piping to the \"safe\" filter. locale Returns the document's Locale object. {{doc.locale}} # Locale object. # Display name of the document's locale in the document's language. {{doc.get_display_name(doc.locale)}} # Display name of the document's locale in English. {{doc.get_display_name('en')}} # Whether the locale's language is RTL (right-to-left). {{doc.locale.is_rtl}} locales Returns a list of Locale objects for the document. {{doc.locales}} path_format Returns the path format for the document, given by $path or the collection's $path. Useful for testing whether a document is built, prior to referencing its URL (which would fail if the document isn't building). {% for item in g.docs('/content/pages') if item.path_format %} {{item.title}} {% endfor %} title Returns the document's canonical title as defined by $title. {{doc.title}} url The document's URL object. {{doc.url}} # The full URL to the document (based on the environment). {{doc.url.path}} # The serving path to the document. {{doc.url.host}} {{doc.url.scheme}} {{doc.url.port}} Built-in fields Built-in fields carry special meaning that can affect various aspects of building your site. The values of built-in fields can change things such as a tag's output in the template API or the routes served by your site. $category The category the document falls into. $category: Get started $date A reference to the document's date defined by the $date field. $dates A function that returns a specific date based on the $dates field. $title: Example Hello World Document $dates: created: 2017-12-01 published: 2017-12-25 {{doc.dates('created')}} # datetime.datetime(2017, 12, 1, 0, 0) {{doc.dates('published')}} # datetime.datetime(2017, 12, 25, 0, 0) $hidden Whether to hide the document when querying for documents with the g.docs tag. Note that even if a document is marked hidden, it will still be rendered and served at its URL. # Document will not show up in g.docs() results. $hidden: true $localization Specify custom localization rules for this document only. Overrides the collection's localization configuration. # Localized documents will have a custom path. $localization: path: /foo/{locale}/{base}/ # Override the locales this document is available in. $localization: locales: - de - it - fr $order Specify the order for the collection's default document order. Negative and decimal values are allowed. $order: 2 $parent Specify the parent document in terms of content hierarchy. Used to auto-generate navigation and content relationships. # Document /content/pages/foo.md becomes the parent. $parent: /content/pages/foo.md $path The serving path to make the document available at. By default, individual documents inherit the path specified by their blueprint. However, it can be overriden by specifying $path at the document-level. # Makes the document available at /foo/bar/. $path: /foo/bar/ # Makes the document available at /foo/. $path: /{base}/ $slug Override the document's slug. By default, the document's slug is derived by slugifying its canonical title. $slug: foo-bar-baz $title The document's canonical title. $title: Canonical Title $titles Specify custom titles for the document to be used in different contexts and by macros. Used by the {{doc.titles()}} function. $title: Really Long Canonical Title $titles: breadcrumb: Breadcrumb Title nav: Nav Title $view The view to use when rendering the page for this document. By default, individual documents inherit the view specified by their blueprint. However, it can be overriden by specifying it at the document-level. # Renders the document with the template at /views/pages.html $view: /views/pages.html", "location": "/reference/documents/", "title": "Documents"}, {"text": "Routes and URLs Grow provides a flexible way to configure the URL serving paths for your site's routes. By leveraging the URL path configuration features, you can easily create clean, maintainable, and flexible URLs for all routes in your site. Philosophy Serving paths and filesystem paths do not need to match one-to-one. This is an explicit capability that exists to remove the need to name internal files a specific way. Because internal file paths do not need to match serving paths, you can change the URL of content at any time without renaming files or performing find and replace operations throughout your site. Configuring URLs There are three places URLs are specified. Your site's routing map is generated by analyzing and combining the rules set in all three locations. podspec.yaml blueprints content documents Content document path formatters Use these formatters to configure serving paths for documents either in a content document or its blueprint. Setting path in both a collection's blueprint and in a content document is optional. You should only define a path in a content document if you need to override a content document's path from the one specified in its blueprint. Remember: don't repeat yourself. If you can specify a path format in a collection's blueprint that generates the right path for all of its documents, then there is no need to also specify $path for each document. Only specify $path in a document for paths you need to override. Path formatter Description {base} The document's basename. Ex: my-page.yaml -> my-page {collection.root} The document's collection's root. {collection.basename} The document's collection's base name. Ex: /content/pages/my-page.yaml -> /pages {collection.sub_path} The document's collection sub directory path. Ex: /content/pages/sub/my-page.yaml -> /sub/ {env.fingerprint} A fingerprint assigned to the build environment. By default this is a timestamp. You can optionally override it by specifying env: fingerprint: in a deployment configuration. {date} The document's date. {locale} The document's locale (or its alias, if one exists). {root} The pod's root as defined in podspec.yaml. {slug} A url slug of the document's title. Examples # In a collection's _blueprint.yaml $path: /pages/{slug}/ $path: /pages/{base}/ $path: /{root}/pages/{base}/ $localization: path: /{locale}/pages/{slug}/ # In document.yaml (only specify document-level paths if you need to override the format set in the blueprint) $path: /pages/home/ $localization: path: /{locale}/pages/home/ Static file path formatters Use these formatters to configure serving paths for static files in podspec.yaml. Path formatter Description {env.fingerprint} A fingerprint assigned to the build environment. By default this is a timestamp. You can optionally override it by specifying env: fingerprint: in a deployment configuration. {fingerprint} A fingerprint uniquely identifying a static file. The fingerprint is a hash of the corresponding static file's contents. Can be used for cache-busting on a per-file basis. {locale} The static file's locale (or its alias, if one exists). {root} The pod's root as defined in podspec.yaml. Examples # In podspec.yaml static_dirs: - static_dir: /source/images/ serve_at: /static/images/ localization: static_dir: /source/{locale}/images/ serve_at: /{locale}/static/images/ Specifying a site root You can specify the site root in podspec.yaml and then reference the root in path formats elsewhere. This provides flexibility should you need to change the site root later, and allows you to avoid repeating the site root throughout multiple configurations. # In podspec.yaml root: /my-site/ # In a collection's _blueprint.yaml path: /{root}/pages/{base}/ Specifying the homepage Most sites have homepages. You can specify your site's homepage in podspec.yaml, which improves automation by providing you with a clickable link to your homepage when the development server starts up. Notifications may also contain links to your homepage, so it's always a good idea to set this. Note that the value of the homepage should point to a content document, not a URL path. Your homepage's URL will be derived from the content document's URL. # In podspec.yaml home: /content/pages/home.yaml URLs in templates Because you are provided with the freedom to change a serving path at any time, whenever you need to reference a URL in a template (such as in a element for a stylesheet or for a link), you should always programmatically generate those URLs using a built-in template function. In general, you should never refer to a linkable resource by its URL: you should refer to it by its internal pod path and leverage either g.doc or g.static to programmatically generate its URL. This technique provides you with flexibility to change URLs later without finding and replacing URLs in your site's code. Plus, it helps avoid broken links. URL object Documents and static files both have url properties that return their corresponding Url object. # The serving path for a content document. {{g.doc('/content/pages/home.yaml').url.path}} # The serving path for a static file. {{g.static('/source/images/image.png').url.path}} {{doc.url}} # The full URL to the document (based on the environment). {{doc.url.path}} # The serving path to the document. {{doc.url.host}} {{doc.url.scheme}} {{doc.url.port}} Relative URLs All URLs generated from a Url object are absolute. However, if you'd like to generate relative URLs, you can use the relative template filter. The final URL generated is relative to the current document context. {{g.doc('/content/pages/home.yaml').url|relative}} Checking routes Use the grow inspect routes command to quickly audit all of the routes that your site generates. You can use this command to avoid building the site and inspecting the generated fileset or saving and refreshing to check paths in the browser. Grow validates your URL path configuration and raises errors upon misconfiguration. For example, Grow will raise an error if you generate the same serving path for two different resources \u2013 no two resources may share the same serving path. Sitemap Grow can autogenerate a sitemap.xml file for your site, upon build. You can enable sitemap generation in podspec.yaml and, optionally, customize which pages and locales are included in the sitemap. # podspec.yaml sitemap: enabled: yes path: \"/{root}/sitemap.xml\" # Optional. collections: # Optional. - pages locales: # Optional. - en - fr", "location": "/reference/urls/", "title": "Routes and URLs"}, {"text": "Content localization In addition to controlling site-wide localization in podspec.yaml, you can create and manage fully localized content at the collection-level or the document-level. Front matter localization You can localize front matter data on a per-locale basis. If you've localized some fields, but not all fields that are specified in the blueprint or default locale, the localized fields will fall back to default locale's fields, cascading from a localized version down to the default version. title@: Title title@fr: Title in FR body@: Body body@fr: Body for FR caption@: Caption # Default {{doc.title}} -> Title {{doc.body}} -> Body {{doc.caption}} -> Caption # FR {{doc.title}} -> Title in FR {{doc.body}} -> Body for FR {{doc.caption}} -> Caption File based localization Similar to the idea of using the @locale localization in the front matter, file names can also be used to manage the localization. The file naming should follow the CLDR codes for locales (case sensitive to support all file systems). For example, files should be named page@en_GB.yaml instead of page@en_gb.yaml. # Content /content/pages/presentation.yaml title@: Title body@: Body caption@: Caption # Content /content/pages/presentation@fr.yaml title: Title in FR body: Body for FR # Default {{doc.title}} -> Title {{doc.body}} -> Body {{doc.caption}} -> Caption # FR {{doc.title}} -> Title in FR {{doc.body}} -> Body for FR {{doc.caption}} -> Caption Locale class Grow's Locale objects subclass the Babel project's Locale class, providing access to some useful data. Grow validates locales and only accepts locales from the Common Locale Data Repository (CLDR), which uses ICU. A full list of compatible locales can be found here. # Page /de/hello/ {{doc.locale.get_language_name('en')}} # German. {{doc.locale.get_language_name('de')}} # Deutsch.", "location": "/reference/content-localization/", "title": "Content localization"}, {"text": "Build environments Environment information is defined in the podspec. Most grow commands default to use the development environment. Some grow commands allow for specifying an environment to use by using the --deployment flag. This allows you to do things like test builds with the environment settings from production. Front matter tagging You can tag front matter data based on the environment information. title@: Title title@env.prod: Title in production title@env.staging: Title in staging # Default {{doc.title}} -> Title # Prod Environment {{doc.title}} -> Title in production # Staging Environment {{doc.title}} -> Title in staging This can also be helpful for preventing specific pages from being deployed to specific deployments. $path: /styleguide/ $path@env.prod: \"\"", "location": "/reference/environments/", "title": "Build environments"}, {"text": "Markdown reference Grow uses the Python-Markdown package for its Markdown implementation. You can see John Gruber's Syntax Documentation to learn about Markdown's default syntax rules. These built-in extensions are enabled by default. Tables Generates tables. View documentation. | Header 1 | Header 2 |-|-| | Row 1 | Content | Row 2 | Content Table of Contents Generates a table of contents based on the headings in a document. View documentation. [\u200bTOC] Configuration Configuration options available to the toc extension can be configured in the podspec. # podspec.yaml markdown: extensions: - kind: toc title: baselevel: 1 anchorlink: False permalink: False separator: \"-\" Include Includes content from another document. # Remove the extra space after `)`. [include('/content/shared/stuff.md') ] URL Url to a document or static file in the pod. # Remove the extra space after `)`. [url('/content/pages/archive.md') ] Sourcecode Implements pygments syntax highlighting for code snippets. [\u200bsourcecode:html] Hello World!

    Source code highlighting. [\u200b/sourcecode] You can also highlight specific lines: [\u200bsourcecode:html, hl_lines=\"1 3\"] Hello World!

    Source code highlighting. [\u200b/sourcecode] Which appears as: Hello World!

    Source code highlighting. Configuration # podspec.yaml markdown: extensions: - kind: sourcecode classes: False # Uses classes instead of inline styles. class_name: code # Class to use on the wrapper div. highlighter: pygments # pygments/plain theme: default # Pygments theme name. If you choose to use classes instead of inline styles you can use pygments to generate the stylesheet for a theme. To generate the styles for the friendly theme with a code class wrapper. pygmentize -S friendly -f html -a .code > styles.css Code Block An alternative to the [sourcecode] block is to use GitHub-flavor backticks via python markdown's code fence extension. `\u200b``js console.log('Hello World'); `\u200b`` You can also highlight specific lines: `\u200b``js hl_lines=\"1\" console.log('Hello World'); `\u200b`` Which would show up as: console.log('Hello World'); Configuration # podspec.yaml markdown: extensions: - kind: markdown.extensions.codehilite classes: False # Uses classes instead of inline styles. class_name: code # Class to use on the wrapper div. highlighter: pygments # pygments/plain theme: default # Pygments theme name. If you choose to use classes instead of inline styles you can use pygments to generate the stylesheet for a theme. To generate the styles for the friendly theme with a code class wrapper. pygmentize -S friendly -f html -a .code > styles.css", "location": "/reference/markdown-extensions/", "title": "Markdown reference"}, {"text": "Translations Translatable items Items that are \"translatable\" are ones which contain text which can be extracted by Grow into message catalogs for translation. Message catalogs can be used to generate translated content. Grow takes a what you tag is what you translate approach: only things that you deem translatable will be extracted for translation, and then subsequently translated upon request. Views UI strings (and other text) in views are translatable. UI strings must be tagged with a template function that indicates the text is translatable. This template function, gettext, has been aliased to {{_(text)}}. {{_('Hello World!')}}

    {{_('Page Title')}}

      {% for callout in g.doc.callouts %}
    • {{_(callout.title)}} \u2013 {{_(callout.description)}} {% endfor %}

    {{_('Posted: %(date)s', date='12/25/86')}} Since Grow translations are opt-in instead of opt-out, it's possible to show translated text from a content document right next to untranslated text. {{doc.title()}} {{_(doc.title())}} Text replacement When doing translations there are two ways to text replacement: {{_('Test out %(name)s in %(text)s', name='Julie', text='indecipherable')}} {{_('Test out {name} in {text}', name='Julie', text='indecipherable')}} Named placeholders should be used as other languages may not use the words in the same order. Content documents Field names postfixed with an @ symbol are translatable. Note that you should omit the @ when referring to the field in a template. The @ is simply used to tag the field for translation in the YAML front matter. # /content/pages/page.yaml (content document) $title@: Hello World! sections: - title@: Section A # Extracted for translation. content@: A's content. - title@: Section B # Extracted for translation. content@: B's content. - title: Section C # Not extracted for translation. content: C's content. items@: # Tagged list of strings. - Item 1. - Item 2. # /views/pages.html (sample usage in a view) {% for section in doc.sections %}

  • {{_(doc.title)}}
  • {{doc.content}} {% endfor %} CSV files Messages can be extracted from CSV files by appending @ to a header cell's value. header1,header2@,header3 Not extracted,Extracted,Not Extracted Translator comments You can provide clarifying details about strings to translators by using translator comments. Upon extraction, translator comments appear alongside their corresponding messages in message catalogs. Translators may then reference the comment in order to produce a more accurate translation. Translator comments are particularly useful to convey restrictions about a string (such as its length) or to clarify context when a string may be ambiguous. # Translator comments in YAML. prop@: Text to translate prop@#: Comment for translator. # Translator comments in templates. {#: Comment for translator. #}

    {{_('Text to translate')}}

    Extracting translations To extract translations into a message catalog, tag all translatable items as explained above, and then use the grow translations extract command. Messages will be extracted to a file /translations/messages.pot. The message catalog (messages.pot) contains all of your pod's extracted messages. This file can then be used to create translation catalogs manually using a PO file editor, or integrated with a translation provider such as Google Translator Toolkit. grow translations extract Extracted translations can also be audited to find content that is untagged for translation. grow translations extract --audit Compiling translations Grow automatically recompiles translations when the development server starts, builds a pod, and during deployment. Translations must be recompiled before they're visible on your site. Importing translations Grow can import translation PO files from external sources. Currently Grow expects a zip file containing one directory named after its locale. Within each directory should be a messages.po file. Alternatively, you can specify a directory instead of a zip file. # Structure of source zip file. /foo.zip /de /messages.po /it/ /messages.po grow translations import --source= Untranslated content To help find content that is in use, but not yet translated you can generate a summary of the missing translations. # Builds pod and shows untranslated strings. grow build --locate-untranslated You can also update the configuration in your podspec to prevent specific deployments when there are untranslated content.", "location": "/reference/translations/", "title": "Translations"}, {"text": "Preprocessors Preprocessors do things like optimization and code generation against your pod's source files. Grow runs preprocessors every time affected source files change, allowing you to \"save and refresh\" to preview your changes. Preprocessors are also run at build time. Grow includes the below preprocessors as built-ins with the SDK, and you'll always be free to bring your own external processing tools (such as Gulp). Global settings By default, preprocessors run when the development server is started and when your site is built. You can control preprocessor execution by using the autorun parameter and optionally by using the name parameter. preprocessors: - name: my_preprocessor kind: autorun: false tags: - red - blue A preprocessor with the above configuration will only be run when using grow preprocess -A or when using grow preprocess -p my_preprocessor. This can be handy to control how often a data-importing preprocessor (such as Google Sheets or Google Docs importers) run. You may not want to run those preprocessors each time your site is built. Kinds Google Docs The Google Docs preprocessor downloads a Google Doc and saves it to a data file within your pod. It can optionally convert the Google Doc to Markdown, ready for use with the markdown filter in templates. Specifying an .md file extension for the path parameter will convert the output to Markdown. After enabling this preprocessor, when you run the grow build command, you will be prompted (once on the command line) to authorize Grow to read your Google Drive files. preprocessors: - kind: google_docs path: /data/filename.{html|md} # Where to save downloaded file. id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI # File ID. convert: true # Whether to convert the file to Markdown. Google Sheets The Google Sheets preprocessor downloads data from a Google Sheet and saves it to a data file within your pod. The data can then be consumed by the g.csv tag, for example, in templates. After enabling this preprocessor, when you run the grow build command, you will be prompted (once on the command line) to authorize Grow to read your Google Drive files. Grow will export data from Google Sheets as either JSON or CSV, depending on the extension used in the path field. preprocessors: - kind: google_sheets path: /content/data/filename.{csv|json|yaml} # Where to save the downloaded file. id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI # Spreadsheet ID. gid: 0 # Worksheet ID (optional). output_style: {compressed|pretty} # Whether to compress or pretty print JSON-formatted docs (default: compressed). By default, Grow treats Google Sheets data as a list. Optionally, the data can be treated as a map and reformatted appropriately. This can be useful for binding a Google Sheet to a content document. Field names beginning with # are ignored when downloaded. The preserve option can be set to builtins to preserve any existing builtin fields in the document (fields whose names begin with $). preprocessors: - kind: google_sheets path: /content/pages/file.yaml id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI format: map preserve: builtins Optionally, data can be saved to a specific key within a YAML document, rather than overwriting an entire document. In the following example, a Google Sheet is downloaded and the faq key within /content/pages/page.yaml is updated with a list of data. preprocessors: - kind: google_sheets path: /content/pages/page.yaml:faq id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI Spreadsheets can also be imported as a collection into Grow. Each sheet will be imported as a separate yaml file that maps the first column to the second column. preprocessors: - kind: google_sheets collection: /content/strings/ id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI An alternative to the map format is the string format which will is the same as the map except it appends a @ to the key name to mark the string for translation. preprocessors: - kind: google_sheets collection: /content/strings/ id: 1ZhJshmT2pZq_IALA6leXJ0oRuKVO12N9BbjAarAT8kI format: string Gulp The Gulp preprocessor simplifies using Gulp in conjunction with Grow. Instead of running Gulp and Grow separately, Grow can manage Gulp as a subprocess and run different Gulp tasks at build and run time. Typically, you would pair grow run with a Gulp task that watches for changes and rebuilds static assets; and you would pair grow build with a Gulp task that builds static assets for release. You can use the build_task and run_task options to control the Gulp task that is run for these two Grow commands. preprocessors: - kind: gulp build_task: \"build\" # Task to run at build time (optional). run_task: \"\" # Task to run when the development server runs (optional).", "location": "/reference/preprocessors/", "title": "Preprocessors"}, {"text": "UI tools Grow's development server comes with the ability to add tools that expand the development experience. Tools Many tools can be found and installed using NPM by looking for the grow-tool- prefix. Some examples include: grow-tool-analytics-highlight Highlights automatically tracked analytics that use data attributes (ex: autotrack). grow-tool-grid Overlays a responsive css grid for checking content alignment. grow-tool-image-swap Allows dragging new image files to temporarily replace images to preview without changing the source. Installing For basic installations: Add the tool to the project's package.json dev dependencies: \"devDependencies\": { \"grow-tool-analytics-highlight\": \"^0.0.5\" } Run grow install to install the new dependency. Update the podspec.yaml to enable the new tool: # Setting for specific deployments. deployments: staging: # Other settings... ui: tools: - kind: image-swap # Settings for dev server. ui: tools: - kind: analytics-highlight options: prefix: event CDNs and Local Sources Tools can also be hosted on third party systems such as CDNs or within the project: ui: tools: - kind: analytics-highlight paths: script: https://some.cdn.com/grow/ui/tool.js style: https://some.cdn.com/grow/ui/tool.css Custom Tools There is an basic example project for creating custom tools: grow-tool-template.", "location": "/reference/ui-tools/", "title": "UI tools"}, {"text": "Command preferences RC file Grow uses a ~/.growrc.yaml file to keep track of global Grow preferences. This file tracks: Auto-update preferences. Timestamp of the last update check. Custom grow command flag defaults. Additionally, Grow will look for a .growrc.yaml file in the directory that the grow command is run. This allows for setting custom Grow preferences for individual projects. Custom Grow command flag defaults For certain command line flags you can provide custom defaults for Grow by adding them to the .growrc.yaml file. Build grow: build: deployment: null preprocess: true clear-cache: false locate-untranslated: false re-route: false Deploy grow: deploy: preprocess: true confirm: true test: true force-untranslated: false Extract grow: extract: include-obsolete: null localized: null include-header: null fuzzy-matching: null Filter grow: filter: include-obsolete: false localized: false include-header: false out-dir: null force: false Import Translations grow: translations: import: include-obsolete: true Preprocess grow: preprocess: deployment: null Run grow: run: deployment: null host: localhost port: 8080 https: false debug: false browser: false update-check: true preprocess: true ui: true re-route: false Stage grow: stage: preprocess: true force-untranslated: false Stats grow: stats: full: true Upload Translations grow: translations: upload: download: true extract: true force: false Shared Command Flag Defaults Some of the flags are common between different Grow commands. These can be done as custom defaults in each command or in the shared settings: grow: shared: deployment: null force-untranslated: false include-header: false include-obsolete: false localized: false out-dir: null preprocess: true re-route: false", "location": "/reference/preferences/", "title": "Command preferences"}, {"text": "Partials Partial templates are a powerful concept that permit site architects to divide a design up into sections, and then freely rearrange and reuse those designs throughout the site. Most pages that can be divided up into discrete sections (such as a header, content area \u2013 or collection of various content areas in order, and a footer) should be implemented using partials. Setting up the partial system Setup the partial system by adding a partial loop to your page template. {# /views/base.html #} {% if doc.partials %} {% for field in doc.partials %} {% if not field.partial %} {% continue %} {% endif %} {# Render the partial with the values in {{partial}}. #} {% set partial_filename = field.partial|expand_partial %} {% with partial = field %} {% include partial_filename with context %} {% endwith %} {% endfor %} {% else %} {{doc.html|safe}} {% endif %} Create partials in the /partials directory. {# /partials/hero/hero.html #}

    {{_(partial.title)}}

    {# /partials/about-me/about-me.html #}

    {{_(partial.title)}}

    {{_(partial.description)}}

    {# /partials/footer/footer.html #}
    Add structured partials to your page front matter # /content/pages/about.yaml $view: /views/base.html $path: /about/ partials: - partial: hero title@: My hero image: !gstatic /static/images/about_me.jpg - partial: about-me title@: About me description@: I am a grow.io user! - partial: footer copyright@: 2017 Mysite.com Now your \u201cabout\u201d page will render a hero, about-me and footer partial. Easily reuse partials across your site pages. Naming partials Name partials in a generic way. The name of the partial should not be coupled to a specific page if possible, but rather the partials\u2019 design. See our full style guide on naming partials. Taking advantage partial system, partials can be easily reused across different pages. You can even selectively render different partials per locale. The following example would should show a different \u201cabout\u201d page for Canada. # /content/pages/about.yaml $view: /views/base.html $path: /about/ partials: - partial: hero title@: My hero image: !gstatic /static/images/about_me.jpg - partial@en_US: about-me title@: About me Description: I am a grow.io user! - partial@en_CA: trip title@: My trip to Canada - partial: footer copyright@: 2017 Mysite.com Keep it DRY Do not repeat yourself and duplicate similar partials. Instead try to create multiple variations within same partial by passing configuration flags or by passing css classes. # /content/pages/about.yaml partials: - partial: hero title@: My hero class@ja_JP: carousel--large carousel_disabled@en_CA: true", "location": "/reference/partials/", "title": "Partials"}, {"text": "Grow implements several commands to help you build your pod to generate files and inspect the pod for ways to improve development and deployment. Commands build Builds a pod, generating all the static files needed to render your site. By default, the grow build command outputs files to the build/ directory within your pod. You can specify a target directory by using an optional fourth argument. In order to deploy your site locally or to a launch destination, see the grow deploy command. # Builds pod to \"build\" directory. grow build # Builds pod to . grow build --out_dir= # Builds pod and shows untranslated strings. grow build --locate-untranslated When using the --locate-untranslated flag Grow will also output all of the untranslated strings into .po files in the .grow/untranslated/ directory to make it easier to request missing translations. preprocess Runs just the preprocessor step of the build process. inspect routes Shows all routes from your pod. Useful for testing and debugging routing. grow inspect routes inspect untranslated Attempts to correlate the strings that are missing translation tagging in front matter and the templates use of the gettext (_(...)) function. grow inspect untranslated", "location": "/workflow/building/", "title": "Building"}, {"text": "Deployment is the act of taking your pod, generating a static site, and transferring it to a web server (or other location), typically ready for serving it publically to the world. Launch lifecycle Steps The launch lifecycle remains the same regardless of your deployment's destination. Here are the steps that every launch undergoes: Processing: All pre and post-processors used by your pod are run. Destination pre-launch: A test is run to verify that Grow can connect to and configure your destination. Deployment index comparison: The deployment index is retrieved from the destination (if it exists), and a diff between what's live and what's about to be deployed is presented to you for confirmation. Deployment The diff between your local index and the deployment index is applied (new files are written, old files are deleted, and edits are made). The destination is configured (if applicable) with things like redirects, custom error pages, etc. Destination post-launch: Any clean up tasks required by the destination are run. The deployment log is updated at the destination. The deployment index is written to the destination. These universal steps ensure that every deployment remains consistent \u2013 and so that future deployments have knowledge of the previous deployment. Configuration You can configure deployments by specifying them in podspec.yaml. The deployments key maps deployment names to destination configurations. # podspec.yaml deployments: default: # Deployment name. destination: local # Destination kind. out_dir: ~/out/ # Parameters for \"local\" destination. grow.io: destination: gcs bucket: grow.io Commands Once you've configured a deployment in podspec.yaml, you can use the grow deploy command to launch your site. This will kick off the deployment process (above). # Deploys your site to a destination named `grow.io`. grow deploy grow.io Destinations Google Cloud Storage Deploys a build to Google Cloud Storage, appropriate for serving directly from GCS using the website serving feature. There are two ways Grow can establish a connection to Google Cloud Storage. You can either use the \"interoperable\" method (which uses an access key and secret, similar to connections to Amazon S3), or you can use a client email address and key file. # Authenticates using access key and secret. destination: gcs bucket: mybucket.example.com # Authenticates using service account email and private key file. destination: gcs bucket: mybucket.example.com project: project-id email: 606734090113-6ink7iugcv89da9sru7lii8bs3i0obqg@developer.gserviceaccount.com key_path: /path/to/key/file.p12 To use the \"interoperable\" method, obtain an access key and secret from the Cloud Console, and place them in $HOME/.boto. You can alternatively place them in environment variables GS_ACCESS_KEY_ID and GS_SECRET_ACCESS_KEY instead of using the .boto file. See documentation on obtaining access keys. # `$HOME/.boto` [Credentials] gs_access_key_id = GOOGTS7C7FUP3AIRVJTE gs_secret_access_key = bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ To use a client email and private key file, visit the Google Developers Console (https://console.developers.google.com/project/apps~YOUR_PROJECT/apiui/credential) and use the email address for the Service Account and download the key using the Generate New Key button. If you do not have a Service Account listed on this screen, use the Create new Client ID button. In addition to obtaining your service account email address and key file, you must make sure that the service account has ownership access to the Google Cloud Storage bucket where you are deploying your site. To do this, make sure the service account's email address is in the bucket's ACL as a User and Owner. You can do this from the Developers Console Cloud Storage UI. Amazon S3 Deploys a build to an Amazon S3 bucket, appropriate for serving directly from S3 using the website serving feature. destination: s3 bucket: mybucket.example.com To authenticate to Amazon S3, obtain your access key and secret and place them in $HOME/.boto. You can also place these environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. [Credentials] aws_access_key_id = ... aws_secret_access_key = ... Local Deploys a build to a local destination on your computer. destination: local out_dir: /path/to/out/directory/ SCP Authenticates using the ssh keys running in ssh-agent. The root_dir option uses syntax from the standard scp command. Values can be either absolute or relative. The host is required. port is optional and will default to 22 if not specified. username is optional and is used to specify the target server username if it differs from your development environment user issuing the grow deploy command. destination: scp host: example.com port: 1111 username: username root_dir: /home/username/domains/example.com/public_html/ Git Deploys a build to a Git repository (either remote or local). Remote repositories are first cloned to a temporary directory, then the specified branch is checked out. The deployment is applied, committed, and then (if the repository is remote), the branch is pushed to the origin. Unless specified otherwise by using the path field, builds are deployed to the root folder of the repository. Git deployments can be used in conjunction with GitHub pages by specifying the gh-pages branch. destination: git repo: https://github.com/owner/project.git branch: master root_dir: Deployment index Documentation incomplete The deployment index is a record of deployment for each pod. The deployment index records the current state of the deployed site, which files exist, when they were deployed, and who performed the deployment. The deployment index is deployed along with generated files with each launch and used to display a diff before each deployment. Environment Deployments can specify environment parameters \u2013 for access in the {{env}} context variable. Use {{env}} to customize template behavior based on the deployment. env: name: prod host: example.com port: 80 scheme: http", "location": "/workflow/deployment/", "title": "Deployment"}, {"text": "You can easily test, build, and/or deploy your website using a continuous integration (CI) system. CI systems remove extra steps from your project's lifecycle and allow you to save time on repetitive tasks. The combination of GitHub, CI, Grow, and a static hosting service such as Google Cloud Storage or Amazon S3 allow you and your team to collaborate on Git and keep your site automatically up to date \u2013 without ever having to run a deploy command. In fact, this is exactly how this documentation is deployed. For security, when doing deployments from CI the CI providers allow you to set environment variables in the UI that can be used in the build but not committed to the repository. Your build steps can make use of these environment variables to authenticate to external services such as Google Cloud Storage or Amazon S3 when deploying. Using Circle CI for automatic deploys Circle CI 2.0 makes use of docker images which can produce faster builds. Grow has a docker image (grow/base) that comes preloaded with grow and some of the common utilities used to build grow sites (like npm and gcloud). Set up your deployment (both the host and the configuration in podspec.yaml) Connect your GitHub repo with Circle CI Configure Circle CI To configure Circle CI, add a .circleci/config.yml file in your repository's root. Any required access keys can be configured as secure environment variables in the settings section of your Circle CI project. Complex Parallel Builds For large sites using a CI service it is possible to break up a build into sharded builds that split the routes then re-combine the build results in a \"fan-in\" deploy. Using Travis CI for automatic deploys Set up your deployment (both the host and the configuration in podspec.yaml). Connect your GitHub repo with Travis CI. Configure Travis CI. To configure Travis CI, add a .travis.yml file in your repository's root. Any required access keys can be configured as secure environment variables in the settings section of your Travis CI project. language: python python: - 2.7 branches: only: - master cache: pip install: pip install grow script: grow deploy --noconfirm grow.io", "location": "/workflow/continuous/", "title": "Continuous integration"}, {"text": "LibYAML fix Grow heavily relies on fast YAML parsing. Grow uses PyYAML, which supports LibYAML C bindings. If the C bindings aren't used, Grow's performance is severely degraded. This is important enough to warrant a warning, so if you received the following message by Grow, you are using the slower pure Python YAML implementation, and not the faster LibYAML version: Warning: libyaml missing, using slower yaml parser. pipenv run grow install attempts to fix this for you automatically, but it may not work reliably depending on your environment. Install LibYAML (once per machine) To fix this, you need to reinstall PyYAML with LibYAML support. If you've never installed LibYAML before, install using the below commands. This only needs to be done once per machine. # On Linux. sudo apt-get install libyaml-dev # On Mac. brew install libyaml Reinstall PyYAML (once per Grow project) Once LibYAML is installed, reinstall PyYAML locally from your project directory: # On Linux. pipenv run pip3 install --global-option=\"--with-libyaml\" --force pyyaml # On Mac. LDFLAGS=\"-L$(brew --prefix)/lib\" \\ CFLAGS=\"-I$(brew --prefix)/include\" \\ pipenv run pip3 install --global-option=\"--with-libyaml\" --force pyyaml Clean up Now, pipenv run grow commands should complete without the libyaml warning. Still having problems? Fast YAML parsing is critical enough to Grow's performance that it is likely worth fixing for your project and environment. Report an issue on GitHub with any information related to your error so we can resolve it.", "location": "/libyaml/", "title": "LibYAML fix"}]}