i18n-and-rtl
Skill0 starsChanged 4 days agoMITView on GitHub
How text is translated and laid out here, with a key in every language file, placeholders, right-to-left layout with directional padding and alignment, the one list of languages and their fonts. Use when adding any visible text, adding or removing a language, or a layout that must work right to left.
In this repository29 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- accessibilitySkill
- actionsSkill
- adding-a-featureSkill
- agent-workflowSkill
- app-contextSkill
- approval-and-safetySkill
- backend-proxySkill
- background-workSkill
- build-an-appSkill
- capture-learningsSkill
- clean-architectureSkill
- customizing-the-assistantSkill
- delegate-to-agentSkill
- edit-boundariesSkill
- model-providersSkill
- performanceSkill
- permissions-and-platformSkill
- read-the-docsSkill
- reliable-mutationsSkill
- routingSkill
- secretsSkill
- state-managementSkill
- storing-dataSkill
- testingSkill
- ui-designSkill
- upgrade-the-frameworkSkill
- verifySkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Don't load this for colors, states and spacing in general.
- Very specific: line 12
Every visible string is a key in every file in assets/lang/ (one per language), read with AppLocalizations.of(context)?.translate(key).
- Very specific: line 25
Add the key to every file in assets/lang/ in the same change.
- Very specific: line 27
Read it in a widget. HomeScreen wraps the call in a helper: AppLocalizations.of(context)?.translate(key) ??
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
i18n and RTL
Don't load this for colors, states and spacing in general; see ui-design.
Rule
- Every visible string is a key in every file in
assets/lang/(one per language), read withAppLocalizations.of(context)?.translate(key). No literal text inText,labelText,hintText,helperText,errorText,tooltip,messageorsemanticLabel. - The files have the same keys as the default language's file and no empty values.
- Layout works right-to-left: use directional classes (
EdgeInsetsDirectional,AlignmentDirectional,TextAlign.start/end), notleft/right. - Languages are defined only in
kSupportedLanguages(lib/domain/entities/language/supported_languages.dart). No code elsewhere checks for a language code.
Enforced by the lint rule no_hardcoded_strings and by test/i18n/translations_test.dart. The narrow-width layout tests run in every listed language and check the direction, so a right-to-left language in the list is covered; no test catches every left/right mistake.
Why
kSupportedLanguages is the one place that defines the languages; the template starts with English and Persian. Each entry holds the code, names, flag and font. The first entry is the default. A missing key shows the raw key. Layout built with left/right stays left-aligned when the language flips.
How
- Add the key to every file in
assets/lang/in the same change. Keys aresnake_case. - That test also pins the total key count of the default language's file. Update the number in
test/i18n/translations_test.dartwhen you add or remove keys. - Read it in a widget.
HomeScreenwraps the call in a helper:AppLocalizations.of(context)?.translate(key) ?? fallback. Keep a fallback for tests that have no delegate. - Placeholders are a literal
{}replaced withreplaceFirst, for example"selected_count": "{} selected"used as_tr('selected_count').replaceFirst('{}', '${selected.length}')inlib/presentation/home/home_screen.dart. Use one{}per string and write each translation so it still reads correctly with the value in place. - Loading:
lib/utils/locale/app_localization.dartloadsassets/lang/<languageCode>.jsonand the delegate's supported locales come fromkSupportedLanguages. Adding a language is its JSON file plus an entry (plus a font if the script needs one); removing one is deleting both. The tests iterate the list and need no edit. The code must be one Flutter'sGlobalMaterialLocalizationssupports; any other needs its ownMaterialLocalizationsdelegate, or Material widgets fail. Steps: the Flutter Agentify guide Add a language. - Layout:
AlignmentDirectional.centerEndandEdgeInsetsDirectional.only(end: 20)in the dismiss background oflib/presentation/home/home_screen.dartare the pattern. Icons that point somewhere (back arrows) must mirror; Material icons do this automatically. - Fonts:
AppTheme.light(locale: ...)passes the locale toAppTypography.setLocaleinlib/core/theme/app_typography.dart, which uses the entry'sfontFamilyandfontFallbacks. Fonts are bundled inassets/fonts/and declared inpubspec.yaml. Another script needs its font bundled and declared there. - Direction: Flutter derives it from the locale (right to left for
fa,ar,heand the like). Don't decide it in code; readDirectionality.of(context). - Receipts: each action writes an English
summaryinlib/domain/actions/and akeywithargs, such askey: 'created_item', args: {'title': created.title}. The chat showsreceipt_<key>from the language file with{title}filled in, or the summary when the key is missing. Addreceipt_<key>to every language file;test/i18n/translations_test.dartlists the receipts that must be there. The action names are translated withaction_<name>keys. - Text typed by the person may be either direction. A
TextFieldfollows the app's direction by default; give it atextDirectiononly where a field must follow its content.
Anti-patterns
Text('Save')ortooltip: 'Close'.- A key added to
en.jsononly. if (locale == 'fa')or aswitchon a language code outsidekSupportedLanguages.EdgeInsets.only(left: 16)orAlignment.centerLeftfor content that should follow the reading direction.- Building a sentence by joining translated pieces; use one key with
{}. - Using
// ignore: flutter_agentify_lints/no_hardcoded_strings.
Verification
dart analyze --fatal-infosreportsno_hardcoded_strings.flutter test test/i18n/translations_test.dart- Switch to a right-to-left language, such as Persian, in Settings (or run
dart run tool/action.dart set_language '{"locale":"fa"}'against the scratch database) and look at the screen. tool/check.shends withAll checks passed.
Related skills
ui-design— states, tokens and widths.accessibility— semantic labels are strings too and need keys.adding-a-feature— the full list for a new screen.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

